From e2fd9f666e5899d8d67cf1b69d1ce39d227ba32b Mon Sep 17 00:00:00 2001 From: CaptainNEO Date: Mon, 7 Mar 2022 20:49:02 +0800 Subject: [PATCH] add goa examples --- README.md | 81 ++++ go/goa_example/cmd/host-cli/grpc.go | 19 + go/goa_example/cmd/host-cli/http.go | 39 ++ go/goa_example/cmd/host-cli/main.go | 124 ++++++ go/goa_example/cmd/host/grpc.go | 82 ++++ go/goa_example/cmd/host/http.go | 112 ++++++ go/goa_example/cmd/host/main.go | 191 +++++++++ go/goa_example/design/design.go | 117 ++++++ go/goa_example/gen/grpc/cli/host/cli.go | 172 +++++++++ .../gen/grpc/service1/client/cli.go | 58 +++ .../gen/grpc/service1/client/client.go | 74 ++++ .../gen/grpc/service1/client/encode_decode.go | 87 +++++ .../gen/grpc/service1/client/types.go | 48 +++ .../pb/goadesign_goagen_service1.pb.go | 363 ++++++++++++++++++ .../pb/goadesign_goagen_service1.proto | 42 ++ .../pb/goadesign_goagen_service1_grpc.pb.go | 145 +++++++ .../gen/grpc/service1/server/encode_decode.go | 109 ++++++ .../gen/grpc/service1/server/server.go | 94 +++++ .../gen/grpc/service1/server/types.go | 51 +++ go/goa_example/gen/http/cli/host/cli.go | 179 +++++++++ go/goa_example/gen/http/openapi.json | 1 + go/goa_example/gen/http/openapi.yaml | 153 ++++++++ go/goa_example/gen/http/openapi3.json | 1 + go/goa_example/gen/http/openapi3.yaml | 129 +++++++ .../gen/http/service1/client/cli.go | 55 +++ .../gen/http/service1/client/client.go | 102 +++++ .../gen/http/service1/client/encode_decode.go | 188 +++++++++ .../gen/http/service1/client/paths.go | 18 + .../gen/http/service1/client/types.go | 109 ++++++ .../gen/http/service1/server/encode_decode.go | 143 +++++++ .../gen/http/service1/server/paths.go | 18 + .../gen/http/service1/server/server.go | 187 +++++++++ .../gen/http/service1/server/types.go | 58 +++ go/goa_example/gen/service1/client.go | 48 +++ go/goa_example/gen/service1/endpoints.go | 75 ++++ go/goa_example/gen/service1/service.go | 80 ++++ go/goa_example/go.mod | 26 ++ go/goa_example/go.sum | 206 ++++++++++ go/goa_example/service1.go | 74 ++++ 39 files changed, 3858 insertions(+) create mode 100644 README.md create mode 100644 go/goa_example/cmd/host-cli/grpc.go create mode 100644 go/goa_example/cmd/host-cli/http.go create mode 100644 go/goa_example/cmd/host-cli/main.go create mode 100644 go/goa_example/cmd/host/grpc.go create mode 100644 go/goa_example/cmd/host/http.go create mode 100644 go/goa_example/cmd/host/main.go create mode 100644 go/goa_example/design/design.go create mode 100644 go/goa_example/gen/grpc/cli/host/cli.go create mode 100644 go/goa_example/gen/grpc/service1/client/cli.go create mode 100644 go/goa_example/gen/grpc/service1/client/client.go create mode 100644 go/goa_example/gen/grpc/service1/client/encode_decode.go create mode 100644 go/goa_example/gen/grpc/service1/client/types.go create mode 100644 go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.pb.go create mode 100644 go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.proto create mode 100644 go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1_grpc.pb.go create mode 100644 go/goa_example/gen/grpc/service1/server/encode_decode.go create mode 100644 go/goa_example/gen/grpc/service1/server/server.go create mode 100644 go/goa_example/gen/grpc/service1/server/types.go create mode 100644 go/goa_example/gen/http/cli/host/cli.go create mode 100644 go/goa_example/gen/http/openapi.json create mode 100644 go/goa_example/gen/http/openapi.yaml create mode 100644 go/goa_example/gen/http/openapi3.json create mode 100644 go/goa_example/gen/http/openapi3.yaml create mode 100644 go/goa_example/gen/http/service1/client/cli.go create mode 100644 go/goa_example/gen/http/service1/client/client.go create mode 100644 go/goa_example/gen/http/service1/client/encode_decode.go create mode 100644 go/goa_example/gen/http/service1/client/paths.go create mode 100644 go/goa_example/gen/http/service1/client/types.go create mode 100644 go/goa_example/gen/http/service1/server/encode_decode.go create mode 100644 go/goa_example/gen/http/service1/server/paths.go create mode 100644 go/goa_example/gen/http/service1/server/server.go create mode 100644 go/goa_example/gen/http/service1/server/types.go create mode 100644 go/goa_example/gen/service1/client.go create mode 100644 go/goa_example/gen/service1/endpoints.go create mode 100644 go/goa_example/gen/service1/service.go create mode 100644 go/goa_example/go.mod create mode 100644 go/goa_example/go.sum create mode 100644 go/goa_example/service1.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..065801e --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# OpenAPI3 Framworks Compare + +本文会横向对比几种支持OpenAPI文档生成的工具/框架。 + +OpenAPI 规范(OAS)定义了一个标准的、语言无关的 RESTful API 接口规范,它可以同时允许开发人员和操作系统查看并理解某个服务的功能,而无需访问源代码,文档或网络流量检查(既方便人类学习和阅读,也方便机器阅读)。正确定义 OAS 后,开发者可以使用最少的实现逻辑来理解远程服务并与之交互。 + +此外,文档生成工具可以使用 OpenAPI 规范来生成 API 文档,代码生成工具可以生成各种编程语言下的服务端和客户端代码,测试代码和其他用例。OpenAPI官方提供了各种语言的服务端和客户端的代码生成工具,比较著名的如[OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator),当然也有很多优秀的第三方开发者开发的工具。 + +> 相关参考 +> +> - [OpenAPI3 Specification官方文档(v3.0.3)](https://spec.openapis.org/oas/v3.0.3) Published 20 February 2020 +> - [OpenAPI3 Specification官方文档(v3.1.0)](https://spec.openapis.org/oas/v3.1.0) Published 15 February 2021 +> - [Awesome OpenAPI3](https://apis.guru/awesome-openapi3) + +## 1. 背景描述 + +使用如上几种框架分别实现Swagger官方用例[petstore](https://petstore.swagger.io)中的一部分,然后分析这些框架的实现方式,和背后生成OpenAPI的逻辑 + +## 2. 参赛选手介绍 + +| 语言 | 框架 | Web功能完备 | OpenAPI版本 | Github Stars | 当前版本 | first release datae | +|--------|--------------------------------------------------------------------------|-------------|-------------|--------------------------------------------------------------------------------|------------------------------------------------------------------------------------|---------------------| +| Go | [goa](https://github.com/goadesign/goa) | 是 | 3 | ![stars](https://img.shields.io/github/stars/goadesign/goa.svg) | ![Release](https://img.shields.io/github/tag/goadesign/goa.svg) | 2016-08-03 | +| Go | [swag](https://github.com/swaggo/swag) | 否 | 2 | ![stars](https://img.shields.io/github/stars/swaggo/swag.svg) | ![Release](https://img.shields.io/github/release/swaggo/swag.svg) | 2017-11-30 | +| Go | [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) | 是 | 2 | ![stars](https://img.shields.io/github/stars/grpc-ecosystem/grpc-gateway.svg) | ![Release](https://img.shields.io/github/release/grpc-ecosystem/grpc-gateway.svg) | 2016-07-11 | +| Go | [fizz](https://github.com/wI2L/fizz) | 是 | 3 | ![stars](https://img.shields.io/github/stars/wI2L/fizz.svg) | ![Release](https://img.shields.io/github/release/wI2L/fizz.svg) | 2019-11-06 | +| Python | [Django REST framework](https://github.com/encode/django-rest-framework) | 是 | 3 | ![stars](https://img.shields.io/github/stars/encode/django-rest-framework.svg) | ![Release](https://img.shields.io/github/release/encode/django-rest-framework.svg) | 2011-02-22 | +| Python | [FastAPI](https://github.com/tiangolo/fastapi) | 是 | 3 | ![stars](https://img.shields.io/github/stars/tiangolo/fastapi.svg) | ![Release](https://img.shields.io/github/release/tiangolo/fastapi.svg) | 2018-12-16 | +| Rust | [Poem](https://github.com/poem-web/poem) | 是 | 3 | ![stars](https://img.shields.io/github/stars/poem-web/poem.svg) | ![Release](https://img.shields.io/github/tag/poem-web/poem.svg) | 2021-10-14 | + +## 3. 实现过程介绍 + +### 1. Goa + +```bash +## 1. 安装goa提供的代码生成工具 +go install goa.design/goa/v3/cmd/goa@v3 + +## 2. 创建一个design文件夹,用于描述API +mkdir -p goa_example/design + +## 3. 使用goa提供的dsl描述API + +## 4. 生成代码模板 +goa gen goa_example/design +# 该步骤会生成gen文件夹中的所有文件,包括design文件中定义的所有接口信息、Model描述、验证方式、Protobuf描述(如果有)等所有相关信息的Go描述 + +## 5. (optional) 生成实现的一个example +goa example goa_example/design +# 该步骤会生成cmd文件夹,包括http server和 grpc server的启动 +# 和项目根目录/{service_name}.go的文件,其中包含了各方法的默认实现(fmt.Println()) +# 接下来只需要修改各方法中的具体实现为真实业务逻辑即可 +``` + +1. 优点 + +## 4. FAQ + +### 1. Swagger和OpenAPI的关系和区别? + +简单来说 + +- OpenAPI: Specification(规范) +- Swagger: Tools for implementing the specification(实现规范的一系列工具) + +Swagger最初是在2010年设计RESTful API的简单开源规范。还开发了包括Swagger UI、Swagger Editor和Swagger Codegen等开源工具,以更好地实现和可视化规范中定义的 API。由规范和开源工具组成的Swagger项目变得非常流行,创建了一个庞大的社区驱动工具生态系统。 + +在2015年,Swagger项目被SmartBear Software收购。Swagger规范被捐赠给Linux基金会并更名为OpenAPI Specification(OAS),是描述REST API的标准规范。 + +此后,Swagger已成为最受欢迎的工具套件,可在整个 API 生命周期中充分利用 OAS 的强大功能。 +SmartBear Software 支持的 Swagger 工具是最流行的实现 OpenAPI 规范的工具之一,并将继续保持 Swagger 名称(Swagger Editor、Swagger UI、SwaggerHub 等) + +### 2. JSON Schema? + + JSON Schema 是一种定义JSON格式的规范,相关生态已经比较完备,各种语言的校验工具基本都有实现。 + 例如vscode中配置文件的代码补全和校验就是基于json schema完成的。 + + OpenAPI中对Json对象的描述就是使用Json schema来描述的 + 目前为止已经发布了多个版本的草案,其中 + OAS3.0.3 采用的是Draft 00 + OAS3.1.0 采用的是Draft 2020-12 diff --git a/go/goa_example/cmd/host-cli/grpc.go b/go/goa_example/cmd/host-cli/grpc.go new file mode 100644 index 0000000..8af8a2e --- /dev/null +++ b/go/goa_example/cmd/host-cli/grpc.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + cli "goa_example/gen/grpc/cli/host" + "os" + + goa "goa.design/goa/v3/pkg" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func doGRPC(scheme, host string, timeout int, debug bool) (goa.Endpoint, interface{}, error) { + conn, err := grpc.Dial(host, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + fmt.Fprintf(os.Stderr, "could not connect to gRPC server at %s: %v\n", host, err) + } + return cli.ParseEndpoint(conn) +} diff --git a/go/goa_example/cmd/host-cli/http.go b/go/goa_example/cmd/host-cli/http.go new file mode 100644 index 0000000..0abb7ee --- /dev/null +++ b/go/goa_example/cmd/host-cli/http.go @@ -0,0 +1,39 @@ +package main + +import ( + cli "goa_example/gen/http/cli/host" + "net/http" + "time" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +func doHTTP(scheme, host string, timeout int, debug bool) (goa.Endpoint, interface{}, error) { + var ( + doer goahttp.Doer + ) + { + doer = &http.Client{Timeout: time.Duration(timeout) * time.Second} + if debug { + doer = goahttp.NewDebugDoer(doer) + } + } + + return cli.ParseEndpoint( + scheme, + host, + doer, + goahttp.RequestEncoder, + goahttp.ResponseDecoder, + debug, + ) +} + +func httpUsageCommands() string { + return cli.UsageCommands() +} + +func httpUsageExamples() string { + return cli.UsageExamples() +} diff --git a/go/goa_example/cmd/host-cli/main.go b/go/goa_example/cmd/host-cli/main.go new file mode 100644 index 0000000..1709410 --- /dev/null +++ b/go/goa_example/cmd/host-cli/main.go @@ -0,0 +1,124 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "net/url" + "os" + "strings" + + goa "goa.design/goa/v3/pkg" +) + +func main() { + var ( + hostF = flag.String("host", "localhost", "Server host (valid values: localhost, integration)") + addrF = flag.String("url", "", "URL to service host") + + verboseF = flag.Bool("verbose", false, "Print request and response details") + vF = flag.Bool("v", false, "Print request and response details") + timeoutF = flag.Int("timeout", 30, "Maximum number of seconds to wait for response") + ) + flag.Usage = usage + flag.Parse() + var ( + addr string + timeout int + debug bool + ) + { + addr = *addrF + if addr == "" { + switch *hostF { + case "localhost": + addr = "http://localhost:8088" + case "integration": + addr = "http://localhost:8088" + default: + fmt.Fprintf(os.Stderr, "invalid host argument: %q (valid hosts: localhost|integration)\n", *hostF) + os.Exit(1) + } + } + timeout = *timeoutF + debug = *verboseF || *vF + } + + var ( + scheme string + host string + ) + { + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + scheme = u.Scheme + host = u.Host + } + var ( + endpoint goa.Endpoint + payload interface{} + err error + ) + { + switch scheme { + case "http", "https": + endpoint, payload, err = doHTTP(scheme, host, timeout, debug) + case "grpc", "grpcs": + endpoint, payload, err = doGRPC(scheme, host, timeout, debug) + default: + fmt.Fprintf(os.Stderr, "invalid scheme: %q (valid schemes: grpc|http)\n", scheme) + os.Exit(1) + } + } + if err != nil { + if err == flag.ErrHelp { + os.Exit(0) + } + fmt.Fprintln(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, "run '"+os.Args[0]+" --help' for detailed usage.") + os.Exit(1) + } + + data, err := endpoint(context.Background(), payload) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + if data != nil { + m, _ := json.MarshalIndent(data, "", " ") + fmt.Println(string(m)) + } +} + +func usage() { + fmt.Fprintf(os.Stderr, `%s is a command line client for the Example Service API. + +Usage: + %s [-host HOST][-url URL][-timeout SECONDS][-verbose|-v] SERVICE ENDPOINT [flags] + + -host HOST: server host (localhost). valid values: localhost, integration + -url URL: specify service URL overriding host URL (http://localhost:8080) + -timeout: maximum number of seconds to wait for response (30) + -verbose|-v: print request and response details (false) + +Commands: +%s +Additional help: + %s SERVICE [ENDPOINT] --help + +Example: +%s +`, os.Args[0], os.Args[0], indent(httpUsageCommands()), os.Args[0], indent(httpUsageExamples())) +} + +func indent(s string) string { + if s == "" { + return "" + } + return " " + strings.Replace(s, "\n", "\n ", -1) +} diff --git a/go/goa_example/cmd/host/grpc.go b/go/goa_example/cmd/host/grpc.go new file mode 100644 index 0000000..6c1a681 --- /dev/null +++ b/go/goa_example/cmd/host/grpc.go @@ -0,0 +1,82 @@ +package main + +import ( + "context" + pet_storepb "goa_example/gen/grpc/pet_store/pb" + petstoresvr "goa_example/gen/grpc/pet_store/server" + petstore "goa_example/gen/pet_store" + "log" + "net" + "net/url" + "sync" + + grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" + grpcmdlwr "goa.design/goa/v3/grpc/middleware" + "goa.design/goa/v3/middleware" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +// handleGRPCServer starts configures and starts a gRPC server on the given +// URL. It shuts down the server if any error is received in the error channel. +func handleGRPCServer(ctx context.Context, u *url.URL, petStoreEndpoints *petstore.Endpoints, wg *sync.WaitGroup, errc chan error, logger *log.Logger, debug bool) { + + // Setup goa log adapter. + var ( + adapter middleware.Logger + ) + { + adapter = middleware.NewLogger(logger) + } + + // Wrap the endpoints with the transport specific layers. The generated + // server packages contains code generated from the design which maps + // the service input and output data structures to gRPC requests and + // responses. + var ( + petStoreServer *petstoresvr.Server + ) + { + petStoreServer = petstoresvr.New(petStoreEndpoints, nil) + } + + // Initialize gRPC server with the middleware. + srv := grpc.NewServer( + grpcmiddleware.WithUnaryServerChain( + grpcmdlwr.UnaryRequestID(), + grpcmdlwr.UnaryServerLog(adapter), + ), + ) + + // Register the servers. + pet_storepb.RegisterPetStoreServer(srv, petStoreServer) + + for svc, info := range srv.GetServiceInfo() { + for _, m := range info.Methods { + logger.Printf("serving gRPC method %s", svc+"/"+m.Name) + } + } + + // Register the server reflection service on the server. + // See https://grpc.github.io/grpc/core/md_doc_server-reflection.html. + reflection.Register(srv) + + (*wg).Add(1) + go func() { + defer (*wg).Done() + + // Start gRPC server in a separate goroutine. + go func() { + lis, err := net.Listen("tcp", u.Host) + if err != nil { + errc <- err + } + logger.Printf("gRPC server listening on %q", u.Host) + errc <- srv.Serve(lis) + }() + + <-ctx.Done() + logger.Printf("shutting down gRPC server at %q", u.Host) + srv.Stop() + }() +} diff --git a/go/goa_example/cmd/host/http.go b/go/goa_example/cmd/host/http.go new file mode 100644 index 0000000..4f24b81 --- /dev/null +++ b/go/goa_example/cmd/host/http.go @@ -0,0 +1,112 @@ +package main + +import ( + "context" + petstoresvr "goa_example/gen/http/pet_store/server" + petstore "goa_example/gen/pet_store" + "log" + "net/http" + "net/url" + "os" + "sync" + "time" + + goahttp "goa.design/goa/v3/http" + httpmdlwr "goa.design/goa/v3/http/middleware" + "goa.design/goa/v3/middleware" +) + +// handleHTTPServer starts configures and starts a HTTP server on the given +// URL. It shuts down the server if any error is received in the error channel. +func handleHTTPServer(ctx context.Context, u *url.URL, petStoreEndpoints *petstore.Endpoints, wg *sync.WaitGroup, errc chan error, logger *log.Logger, debug bool) { + + // Setup goa log adapter. + var ( + adapter middleware.Logger + ) + { + adapter = middleware.NewLogger(logger) + } + + // Provide the transport specific request decoder and response encoder. + // The goa http package has built-in support for JSON, XML and gob. + // Other encodings can be used by providing the corresponding functions, + // see goa.design/implement/encoding. + var ( + dec = goahttp.RequestDecoder + enc = goahttp.ResponseEncoder + ) + + // Build the service HTTP request multiplexer and configure it to serve + // HTTP requests to the service endpoints. + var mux goahttp.Muxer + { + mux = goahttp.NewMuxer() + } + + // Wrap the endpoints with the transport specific layers. The generated + // server packages contains code generated from the design which maps + // the service input and output data structures to HTTP requests and + // responses. + var ( + petStoreServer *petstoresvr.Server + ) + { + eh := errorHandler(logger) + petStoreServer = petstoresvr.New(petStoreEndpoints, mux, dec, enc, eh, nil) + if debug { + servers := goahttp.Servers{ + petStoreServer, + } + servers.Use(httpmdlwr.Debug(mux, os.Stdout)) + } + } + // Configure the mux. + petstoresvr.Mount(mux, petStoreServer) + + // Wrap the multiplexer with additional middlewares. Middlewares mounted + // here apply to all the service endpoints. + var handler http.Handler = mux + { + handler = httpmdlwr.Log(adapter)(handler) + handler = httpmdlwr.RequestID()(handler) + } + + // Start HTTP server using default configuration, change the code to + // configure the server as required by your service. + srv := &http.Server{Addr: u.Host, Handler: handler} + for _, m := range petStoreServer.Mounts { + logger.Printf("HTTP %q mounted on %s %s", m.Method, m.Verb, m.Pattern) + } + + (*wg).Add(1) + go func() { + defer (*wg).Done() + + // Start HTTP server in a separate goroutine. + go func() { + logger.Printf("HTTP server listening on %q", u.Host) + errc <- srv.ListenAndServe() + }() + + <-ctx.Done() + logger.Printf("shutting down HTTP server at %q", u.Host) + + // Shutdown gracefully with a 30s timeout. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + _ = srv.Shutdown(ctx) + }() +} + +// errorHandler returns a function that writes and logs the given error. +// The function also writes and logs the error unique ID so that it's possible +// to correlate. +func errorHandler(logger *log.Logger) func(context.Context, http.ResponseWriter, error) { + return func(ctx context.Context, w http.ResponseWriter, err error) { + id := ctx.Value(middleware.RequestIDKey).(string) + _, _ = w.Write([]byte("[" + id + "] encoding: " + err.Error())) + logger.Printf("[%s] ERROR: %s", id, err.Error()) + } +} diff --git a/go/goa_example/cmd/host/main.go b/go/goa_example/cmd/host/main.go new file mode 100644 index 0000000..cad4f3e --- /dev/null +++ b/go/goa_example/cmd/host/main.go @@ -0,0 +1,191 @@ +package main + +import ( + "context" + "flag" + "fmt" + exampleservice "goa_example" + petstore "goa_example/gen/pet_store" + "log" + "net" + "net/url" + "os" + "os/signal" + "sync" + "syscall" +) + +func main() { + // Define command line flags, add any other flag required to configure the + // service. + var ( + hostF = flag.String("host", "localhost", "Server host (valid values: localhost, integration)") + domainF = flag.String("domain", "", "Host domain name (overrides host domain specified in service design)") + httpPortF = flag.String("http-port", "", "HTTP port (overrides host HTTP port specified in service design)") + grpcPortF = flag.String("grpc-port", "", "gRPC port (overrides host gRPC port specified in service design)") + secureF = flag.Bool("secure", false, "Use secure scheme (https or grpcs)") + dbgF = flag.Bool("debug", false, "Log request and response bodies") + ) + flag.Parse() + + // Setup logger. Replace logger with your own log package of choice. + var ( + logger *log.Logger + ) + { + logger = log.New(os.Stderr, "[exampleservice] ", log.Ltime) + } + + // Initialize the services. + var ( + petStoreSvc petstore.Service + ) + { + petStoreSvc = exampleservice.NewPetStore(logger) + } + + // Wrap the services in endpoints that can be invoked from other services + // potentially running in different processes. + var ( + petStoreEndpoints *petstore.Endpoints + ) + { + petStoreEndpoints = petstore.NewEndpoints(petStoreSvc) + } + + // Create channel used by both the signal handler and server goroutines + // to notify the main goroutine when to stop the server. + errc := make(chan error) + + // Setup interrupt handler. This optional step configures the process so + // that SIGINT and SIGTERM signals cause the services to stop gracefully. + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + errc <- fmt.Errorf("%s", <-c) + }() + + var wg sync.WaitGroup + ctx, cancel := context.WithCancel(context.Background()) + + // Start the servers and send errors (if any) to the error channel. + switch *hostF { + case "localhost": + { + addr := "http://localhost:8088" + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + if *secureF { + u.Scheme = "https" + } + if *domainF != "" { + u.Host = *domainF + } + if *httpPortF != "" { + h, _, err := net.SplitHostPort(u.Host) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", u.Host, err) + os.Exit(1) + } + u.Host = net.JoinHostPort(h, *httpPortF) + } else if u.Port() == "" { + u.Host = net.JoinHostPort(u.Host, "80") + } + handleHTTPServer(ctx, u, petStoreEndpoints, &wg, errc, logger, *dbgF) + } + + { + addr := "grpc://localhost:8080" + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + if *secureF { + u.Scheme = "grpcs" + } + if *domainF != "" { + u.Host = *domainF + } + if *grpcPortF != "" { + h, _, err := net.SplitHostPort(u.Host) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", u.Host, err) + os.Exit(1) + } + u.Host = net.JoinHostPort(h, *grpcPortF) + } else if u.Port() == "" { + u.Host = net.JoinHostPort(u.Host, "8080") + } + handleGRPCServer(ctx, u, petStoreEndpoints, &wg, errc, logger, *dbgF) + } + + case "integration": + { + addr := "http://localhost:8088" + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + if *secureF { + u.Scheme = "https" + } + if *domainF != "" { + u.Host = *domainF + } + if *httpPortF != "" { + h, _, err := net.SplitHostPort(u.Host) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", u.Host, err) + os.Exit(1) + } + u.Host = net.JoinHostPort(h, *httpPortF) + } else if u.Port() == "" { + u.Host = net.JoinHostPort(u.Host, "80") + } + handleHTTPServer(ctx, u, petStoreEndpoints, &wg, errc, logger, *dbgF) + } + + { + addr := "grpc://localhost:8080" + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + if *secureF { + u.Scheme = "grpcs" + } + if *domainF != "" { + u.Host = *domainF + } + if *grpcPortF != "" { + h, _, err := net.SplitHostPort(u.Host) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", u.Host, err) + os.Exit(1) + } + u.Host = net.JoinHostPort(h, *grpcPortF) + } else if u.Port() == "" { + u.Host = net.JoinHostPort(u.Host, "8080") + } + handleGRPCServer(ctx, u, petStoreEndpoints, &wg, errc, logger, *dbgF) + } + + default: + fmt.Fprintf(os.Stderr, "invalid host argument: %q (valid hosts: localhost|integration)\n", *hostF) + } + + // Wait for signal. + logger.Printf("exiting (%v)", <-errc) + + // Send cancellation signal to the goroutines. + cancel() + + wg.Wait() + logger.Println("exited") +} diff --git a/go/goa_example/design/design.go b/go/goa_example/design/design.go new file mode 100644 index 0000000..9a45876 --- /dev/null +++ b/go/goa_example/design/design.go @@ -0,0 +1,117 @@ +package design + +import . "goa.design/goa/v3/dsl" + +// 描述一个API的基本信息 +var _ = API("Example Service", func() { + Title("A Goa Example Service") + Description("HTTP service for test") + Server("host", func() { + Host("localhost", func() { URI("http://localhost:8088") }) + Host("integration", func() { URI("http://localhost:8088") }) + }) +}) + +// JWTAuth 描述了一个security scheme使用JWT tokens. +var JWTAuth = JWTSecurity("jwt", func() { + Description(`Secures endpoint by requiring a valid JWT token retrieved via the signin endpoint. Supports scopes "api:read" and "api:write".`) +}) + +// BasicAuth 描述了一个security scheme使用basic authentication. +var BasicAuth = BasicAuthSecurity("basic", func() { + Description("Basic authentication used to authenticate security principal during signin") +}) + +// Creds 描述了一个Json对象,包含3个字段 +var Creds = Type("Creds", func() { + Field(1, "jwt", String, "JWT token", func() { + Example("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ") + }) + Field(2, "api_key", String, "API Key", func() { + Example("abcdef12345") + }) + Field(3, "oauth_token", String, "OAuth2 token", func() { + Example("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ") + }) + Required("jwt", "api_key", "oauth_token") +}) + +// 使用Service描述一个服务 +var _ = Service("Service1", func() { + // 服务的描述信息 + Description("The secured service exposes endpoints that require valid authorization credentials.") + // 该服务可能出现的异常情况 + Error("unauthorized", String, "Credentials are invalid") + + // 描述本服务全局可能可能返回的异常情况的状态码 + HTTP(func() { + // 会匹配Error中描述的unauthorized + Response("unauthorized", StatusUnauthorized) + }) + GRPC(func() { + Response("unauthorized", CodeUnauthenticated) + }) + + // 使用Method描述一个具体的请求(Operation)或grpc方法 + Method("signin", func() { + // 本方法使用BasicAuth进行认证 + Security(BasicAuth) + // 使用Payload描述请求的参数信息(Parameters) + // 如下描述了一个简单的包含了两个参数的请求 + Payload(func() { + Description("Credentials used to authenticate to retrieve JWT token") + UsernameField(1, "username", String, "Username used to perform signin", func() { + Example("user") + }) + PasswordField(2, "password", String, "Password used to perform signin", func() { + Example("password") + }) + Required("username", "password") + }) + // 接口正常时的返回结果 + Result(Creds) + // HTTP描述 + HTTP(func() { + // 使用POST方法请求,这个时候Payload会以JSON Body的形式传入 + POST("/signin") + // 接口返回时可能出现的状态码 + Response(StatusOK) + Response(StatusBadRequest) + }) + // GRPC描述 + GRPC(func() { + // 接口返回时可能出现的状态码 + Response(CodeOK) + Response(CodeInternal) + }) + }) + + Method("secure", func() { + Description("这是一个需要JWT认证的接口") + // 定义使用JWT 认证 + Security(JWTAuth) + // Payload信息 + Payload(func() { + Field(1, "fail", Boolean, func() { + Description("Whether to force auth failure even with a valid JWT") + }) + // 特殊的Field,用于让Goa识别该字段为Token,且在Header中 + TokenField(2, "token", String, func() { + Description("JWT used for authentication") + }) + Required("token") + }) + + // 返回的类型为字符串 + Result(String) + + HTTP(func() { + GET("/secure") + Response(StatusOK) + }) + + GRPC(func() { + Response(CodeOK) + }) + }) +}) diff --git a/go/goa_example/gen/grpc/cli/host/cli.go b/go/goa_example/gen/grpc/cli/host/cli.go new file mode 100644 index 0000000..f518f68 --- /dev/null +++ b/go/goa_example/gen/grpc/cli/host/cli.go @@ -0,0 +1,172 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// host gRPC client CLI support package +// +// Command: +// $ goa gen goa_example/design + +package cli + +import ( + "flag" + "fmt" + service1c "goa_example/gen/grpc/service1/client" + "os" + + goa "goa.design/goa/v3/pkg" + grpc "google.golang.org/grpc" +) + +// UsageCommands returns the set of commands and sub-commands using the format +// +// command (subcommand1|subcommand2|...) +// +func UsageCommands() string { + return `service1 (signin|secure) +` +} + +// UsageExamples produces an example of a valid invocation of the CLI tool. +func UsageExamples() string { + return os.Args[0] + ` service1 signin --username "user" --password "password"` + "\n" + + "" +} + +// ParseEndpoint returns the endpoint and payload as specified on the command +// line. +func ParseEndpoint(cc *grpc.ClientConn, opts ...grpc.CallOption) (goa.Endpoint, interface{}, error) { + var ( + service1Flags = flag.NewFlagSet("service1", flag.ContinueOnError) + + service1SigninFlags = flag.NewFlagSet("signin", flag.ExitOnError) + service1SigninUsernameFlag = service1SigninFlags.String("username", "REQUIRED", "") + service1SigninPasswordFlag = service1SigninFlags.String("password", "REQUIRED", "") + + service1SecureFlags = flag.NewFlagSet("secure", flag.ExitOnError) + service1SecureMessageFlag = service1SecureFlags.String("message", "", "") + service1SecureTokenFlag = service1SecureFlags.String("token", "REQUIRED", "") + ) + service1Flags.Usage = service1Usage + service1SigninFlags.Usage = service1SigninUsage + service1SecureFlags.Usage = service1SecureUsage + + if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { + return nil, nil, err + } + + if flag.NArg() < 2 { // two non flag args are required: SERVICE and ENDPOINT (aka COMMAND) + return nil, nil, fmt.Errorf("not enough arguments") + } + + var ( + svcn string + svcf *flag.FlagSet + ) + { + svcn = flag.Arg(0) + switch svcn { + case "service1": + svcf = service1Flags + default: + return nil, nil, fmt.Errorf("unknown service %q", svcn) + } + } + if err := svcf.Parse(flag.Args()[1:]); err != nil { + return nil, nil, err + } + + var ( + epn string + epf *flag.FlagSet + ) + { + epn = svcf.Arg(0) + switch svcn { + case "service1": + switch epn { + case "signin": + epf = service1SigninFlags + + case "secure": + epf = service1SecureFlags + + } + + } + } + if epf == nil { + return nil, nil, fmt.Errorf("unknown %q endpoint %q", svcn, epn) + } + + // Parse endpoint flags if any + if svcf.NArg() > 1 { + if err := epf.Parse(svcf.Args()[1:]); err != nil { + return nil, nil, err + } + } + + var ( + data interface{} + endpoint goa.Endpoint + err error + ) + { + switch svcn { + case "service1": + c := service1c.NewClient(cc, opts...) + switch epn { + case "signin": + endpoint = c.Signin() + data, err = service1c.BuildSigninPayload(*service1SigninUsernameFlag, *service1SigninPasswordFlag) + case "secure": + endpoint = c.Secure() + data, err = service1c.BuildSecurePayload(*service1SecureMessageFlag, *service1SecureTokenFlag) + } + } + } + if err != nil { + return nil, nil, err + } + + return endpoint, data, nil +} + +// service1Usage displays the usage of the service1 command and its subcommands. +func service1Usage() { + fmt.Fprintf(os.Stderr, `The secured service exposes endpoints that require valid authorization credentials. +Usage: + %[1]s [globalflags] service1 COMMAND [flags] + +COMMAND: + signin: Signin implements signin. + secure: 这是一个需要JWT认证的接口 + +Additional help: + %[1]s service1 COMMAND --help +`, os.Args[0]) +} +func service1SigninUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] service1 signin -username STRING -password STRING + +Signin implements signin. + -username STRING: + -password STRING: + +Example: + %[1]s service1 signin --username "user" --password "password" +`, os.Args[0]) +} + +func service1SecureUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] service1 secure -message JSON -token STRING + +这是一个需要JWT认证的接口 + -message JSON: + -token STRING: + +Example: + %[1]s service1 secure --message '{ + "fail": true + }' --token "Quia omnis amet et rerum quis." +`, os.Args[0]) +} diff --git a/go/goa_example/gen/grpc/service1/client/cli.go b/go/goa_example/gen/grpc/service1/client/cli.go new file mode 100644 index 0000000..3e9c6ee --- /dev/null +++ b/go/goa_example/gen/grpc/service1/client/cli.go @@ -0,0 +1,58 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC client CLI support package +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + "encoding/json" + "fmt" + service1pb "goa_example/gen/grpc/service1/pb" + service1 "goa_example/gen/service1" +) + +// BuildSigninPayload builds the payload for the Service1 signin endpoint from +// CLI flags. +func BuildSigninPayload(service1SigninUsername string, service1SigninPassword string) (*service1.SigninPayload, error) { + var username string + { + username = service1SigninUsername + } + var password string + { + password = service1SigninPassword + } + v := &service1.SigninPayload{} + v.Username = username + v.Password = password + + return v, nil +} + +// BuildSecurePayload builds the payload for the Service1 secure endpoint from +// CLI flags. +func BuildSecurePayload(service1SecureMessage string, service1SecureToken string) (*service1.SecurePayload, error) { + var err error + var message service1pb.SecureRequest + { + if service1SecureMessage != "" { + err = json.Unmarshal([]byte(service1SecureMessage), &message) + if err != nil { + return nil, fmt.Errorf("invalid JSON for message, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"fail\": true\n }'") + } + } + } + var token string + { + token = service1SecureToken + } + v := &service1.SecurePayload{ + Fail: &message.Fail, + } + v.Token = token + + return v, nil +} diff --git a/go/goa_example/gen/grpc/service1/client/client.go b/go/goa_example/gen/grpc/service1/client/client.go new file mode 100644 index 0000000..af43010 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/client/client.go @@ -0,0 +1,74 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC client +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + "context" + service1pb "goa_example/gen/grpc/service1/pb" + + goagrpc "goa.design/goa/v3/grpc" + goapb "goa.design/goa/v3/grpc/pb" + goa "goa.design/goa/v3/pkg" + "google.golang.org/grpc" +) + +// Client lists the service endpoint gRPC clients. +type Client struct { + grpccli service1pb.Service1Client + opts []grpc.CallOption +} + +// NewClient instantiates gRPC client for all the Service1 service servers. +func NewClient(cc *grpc.ClientConn, opts ...grpc.CallOption) *Client { + return &Client{ + grpccli: service1pb.NewService1Client(cc), + opts: opts, + } +} + +// Signin calls the "Signin" function in service1pb.Service1Client interface. +func (c *Client) Signin() goa.Endpoint { + return func(ctx context.Context, v interface{}) (interface{}, error) { + inv := goagrpc.NewInvoker( + BuildSigninFunc(c.grpccli, c.opts...), + EncodeSigninRequest, + DecodeSigninResponse) + res, err := inv.Invoke(ctx, v) + if err != nil { + resp := goagrpc.DecodeError(err) + switch message := resp.(type) { + case *goapb.ErrorResponse: + return nil, goagrpc.NewServiceError(message) + default: + return nil, goa.Fault(err.Error()) + } + } + return res, nil + } +} + +// Secure calls the "Secure" function in service1pb.Service1Client interface. +func (c *Client) Secure() goa.Endpoint { + return func(ctx context.Context, v interface{}) (interface{}, error) { + inv := goagrpc.NewInvoker( + BuildSecureFunc(c.grpccli, c.opts...), + EncodeSecureRequest, + DecodeSecureResponse) + res, err := inv.Invoke(ctx, v) + if err != nil { + resp := goagrpc.DecodeError(err) + switch message := resp.(type) { + case *goapb.ErrorResponse: + return nil, goagrpc.NewServiceError(message) + default: + return nil, goa.Fault(err.Error()) + } + } + return res, nil + } +} diff --git a/go/goa_example/gen/grpc/service1/client/encode_decode.go b/go/goa_example/gen/grpc/service1/client/encode_decode.go new file mode 100644 index 0000000..e626680 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/client/encode_decode.go @@ -0,0 +1,87 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC client encoders and decoders +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + "context" + service1pb "goa_example/gen/grpc/service1/pb" + service1 "goa_example/gen/service1" + + goagrpc "goa.design/goa/v3/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// BuildSigninFunc builds the remote method to invoke for "Service1" service +// "signin" endpoint. +func BuildSigninFunc(grpccli service1pb.Service1Client, cliopts ...grpc.CallOption) goagrpc.RemoteFunc { + return func(ctx context.Context, reqpb interface{}, opts ...grpc.CallOption) (interface{}, error) { + for _, opt := range cliopts { + opts = append(opts, opt) + } + if reqpb != nil { + return grpccli.Signin(ctx, reqpb.(*service1pb.SigninRequest), opts...) + } + return grpccli.Signin(ctx, &service1pb.SigninRequest{}, opts...) + } +} + +// EncodeSigninRequest encodes requests sent to Service1 signin endpoint. +func EncodeSigninRequest(ctx context.Context, v interface{}, md *metadata.MD) (interface{}, error) { + payload, ok := v.(*service1.SigninPayload) + if !ok { + return nil, goagrpc.ErrInvalidType("Service1", "signin", "*service1.SigninPayload", v) + } + (*md).Append("username", payload.Username) + (*md).Append("password", payload.Password) + return NewSigninRequest(), nil +} + +// DecodeSigninResponse decodes responses from the Service1 signin endpoint. +func DecodeSigninResponse(ctx context.Context, v interface{}, hdr, trlr metadata.MD) (interface{}, error) { + message, ok := v.(*service1pb.SigninResponse) + if !ok { + return nil, goagrpc.ErrInvalidType("Service1", "signin", "*service1pb.SigninResponse", v) + } + res := NewSigninResult(message) + return res, nil +} + +// BuildSecureFunc builds the remote method to invoke for "Service1" service +// "secure" endpoint. +func BuildSecureFunc(grpccli service1pb.Service1Client, cliopts ...grpc.CallOption) goagrpc.RemoteFunc { + return func(ctx context.Context, reqpb interface{}, opts ...grpc.CallOption) (interface{}, error) { + for _, opt := range cliopts { + opts = append(opts, opt) + } + if reqpb != nil { + return grpccli.Secure(ctx, reqpb.(*service1pb.SecureRequest), opts...) + } + return grpccli.Secure(ctx, &service1pb.SecureRequest{}, opts...) + } +} + +// EncodeSecureRequest encodes requests sent to Service1 secure endpoint. +func EncodeSecureRequest(ctx context.Context, v interface{}, md *metadata.MD) (interface{}, error) { + payload, ok := v.(*service1.SecurePayload) + if !ok { + return nil, goagrpc.ErrInvalidType("Service1", "secure", "*service1.SecurePayload", v) + } + (*md).Append("authorization", payload.Token) + return NewSecureRequest(payload), nil +} + +// DecodeSecureResponse decodes responses from the Service1 secure endpoint. +func DecodeSecureResponse(ctx context.Context, v interface{}, hdr, trlr metadata.MD) (interface{}, error) { + message, ok := v.(*service1pb.SecureResponse) + if !ok { + return nil, goagrpc.ErrInvalidType("Service1", "secure", "*service1pb.SecureResponse", v) + } + res := NewSecureResult(message) + return res, nil +} diff --git a/go/goa_example/gen/grpc/service1/client/types.go b/go/goa_example/gen/grpc/service1/client/types.go new file mode 100644 index 0000000..b2269a6 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/client/types.go @@ -0,0 +1,48 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC client types +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + service1pb "goa_example/gen/grpc/service1/pb" + service1 "goa_example/gen/service1" +) + +// NewSigninRequest builds the gRPC request type from the payload of the +// "signin" endpoint of the "Service1" service. +func NewSigninRequest() *service1pb.SigninRequest { + message := &service1pb.SigninRequest{} + return message +} + +// NewSigninResult builds the result type of the "signin" endpoint of the +// "Service1" service from the gRPC response type. +func NewSigninResult(message *service1pb.SigninResponse) *service1.Creds { + result := &service1.Creds{ + JWT: message.Jwt, + APIKey: message.ApiKey, + OauthToken: message.OauthToken, + } + return result +} + +// NewSecureRequest builds the gRPC request type from the payload of the +// "secure" endpoint of the "Service1" service. +func NewSecureRequest(payload *service1.SecurePayload) *service1pb.SecureRequest { + message := &service1pb.SecureRequest{} + if payload.Fail != nil { + message.Fail = *payload.Fail + } + return message +} + +// NewSecureResult builds the result type of the "secure" endpoint of the +// "Service1" service from the gRPC response type. +func NewSecureResult(message *service1pb.SecureResponse) string { + result := message.Field + return result +} diff --git a/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.pb.go b/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.pb.go new file mode 100644 index 0000000..c10a335 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.pb.go @@ -0,0 +1,363 @@ +// Code generated with goa v3.6.0, DO NOT EDIT. +// +// Service1 protocol buffer definition +// +// Command: +// $ goa gen goa_example/design + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.4 +// source: goadesign_goagen_service1.proto + +package service1pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SigninRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SigninRequest) Reset() { + *x = SigninRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_goadesign_goagen_service1_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SigninRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SigninRequest) ProtoMessage() {} + +func (x *SigninRequest) ProtoReflect() protoreflect.Message { + mi := &file_goadesign_goagen_service1_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SigninRequest.ProtoReflect.Descriptor instead. +func (*SigninRequest) Descriptor() ([]byte, []int) { + return file_goadesign_goagen_service1_proto_rawDescGZIP(), []int{0} +} + +type SigninResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JWT token + Jwt string `protobuf:"bytes,1,opt,name=jwt,proto3" json:"jwt,omitempty"` + // API Key + ApiKey string `protobuf:"bytes,2,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"` + // OAuth2 token + OauthToken string `protobuf:"bytes,3,opt,name=oauth_token,json=oauthToken,proto3" json:"oauth_token,omitempty"` +} + +func (x *SigninResponse) Reset() { + *x = SigninResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_goadesign_goagen_service1_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SigninResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SigninResponse) ProtoMessage() {} + +func (x *SigninResponse) ProtoReflect() protoreflect.Message { + mi := &file_goadesign_goagen_service1_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SigninResponse.ProtoReflect.Descriptor instead. +func (*SigninResponse) Descriptor() ([]byte, []int) { + return file_goadesign_goagen_service1_proto_rawDescGZIP(), []int{1} +} + +func (x *SigninResponse) GetJwt() string { + if x != nil { + return x.Jwt + } + return "" +} + +func (x *SigninResponse) GetApiKey() string { + if x != nil { + return x.ApiKey + } + return "" +} + +func (x *SigninResponse) GetOauthToken() string { + if x != nil { + return x.OauthToken + } + return "" +} + +type SecureRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Whether to force auth failure even with a valid JWT + Fail bool `protobuf:"varint,1,opt,name=fail,proto3" json:"fail,omitempty"` +} + +func (x *SecureRequest) Reset() { + *x = SecureRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_goadesign_goagen_service1_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecureRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecureRequest) ProtoMessage() {} + +func (x *SecureRequest) ProtoReflect() protoreflect.Message { + mi := &file_goadesign_goagen_service1_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecureRequest.ProtoReflect.Descriptor instead. +func (*SecureRequest) Descriptor() ([]byte, []int) { + return file_goadesign_goagen_service1_proto_rawDescGZIP(), []int{2} +} + +func (x *SecureRequest) GetFail() bool { + if x != nil { + return x.Fail + } + return false +} + +type SecureResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` +} + +func (x *SecureResponse) Reset() { + *x = SecureResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_goadesign_goagen_service1_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecureResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecureResponse) ProtoMessage() {} + +func (x *SecureResponse) ProtoReflect() protoreflect.Message { + mi := &file_goadesign_goagen_service1_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecureResponse.ProtoReflect.Descriptor instead. +func (*SecureResponse) Descriptor() ([]byte, []int) { + return file_goadesign_goagen_service1_proto_rawDescGZIP(), []int{3} +} + +func (x *SecureResponse) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +var File_goadesign_goagen_service1_proto protoreflect.FileDescriptor + +var file_goadesign_goagen_service1_proto_rawDesc = []byte{ + 0x0a, 0x1f, 0x67, 0x6f, 0x61, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x67, 0x6f, 0x61, 0x67, + 0x65, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x31, 0x22, 0x0f, 0x0a, 0x0d, 0x53, + 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5c, 0x0a, 0x0e, + 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x6a, 0x77, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6a, 0x77, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x61, 0x75, + 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x6f, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x23, 0x0a, 0x0d, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, + 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x22, + 0x26, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x84, 0x01, 0x0a, 0x08, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x31, 0x12, 0x3b, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x12, 0x17, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x17, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x31, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0d, + 0x5a, 0x0b, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x31, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_goadesign_goagen_service1_proto_rawDescOnce sync.Once + file_goadesign_goagen_service1_proto_rawDescData = file_goadesign_goagen_service1_proto_rawDesc +) + +func file_goadesign_goagen_service1_proto_rawDescGZIP() []byte { + file_goadesign_goagen_service1_proto_rawDescOnce.Do(func() { + file_goadesign_goagen_service1_proto_rawDescData = protoimpl.X.CompressGZIP(file_goadesign_goagen_service1_proto_rawDescData) + }) + return file_goadesign_goagen_service1_proto_rawDescData +} + +var file_goadesign_goagen_service1_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_goadesign_goagen_service1_proto_goTypes = []interface{}{ + (*SigninRequest)(nil), // 0: service1.SigninRequest + (*SigninResponse)(nil), // 1: service1.SigninResponse + (*SecureRequest)(nil), // 2: service1.SecureRequest + (*SecureResponse)(nil), // 3: service1.SecureResponse +} +var file_goadesign_goagen_service1_proto_depIdxs = []int32{ + 0, // 0: service1.Service1.Signin:input_type -> service1.SigninRequest + 2, // 1: service1.Service1.Secure:input_type -> service1.SecureRequest + 1, // 2: service1.Service1.Signin:output_type -> service1.SigninResponse + 3, // 3: service1.Service1.Secure:output_type -> service1.SecureResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_goadesign_goagen_service1_proto_init() } +func file_goadesign_goagen_service1_proto_init() { + if File_goadesign_goagen_service1_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_goadesign_goagen_service1_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SigninRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_goadesign_goagen_service1_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SigninResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_goadesign_goagen_service1_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecureRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_goadesign_goagen_service1_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecureResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_goadesign_goagen_service1_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_goadesign_goagen_service1_proto_goTypes, + DependencyIndexes: file_goadesign_goagen_service1_proto_depIdxs, + MessageInfos: file_goadesign_goagen_service1_proto_msgTypes, + }.Build() + File_goadesign_goagen_service1_proto = out.File + file_goadesign_goagen_service1_proto_rawDesc = nil + file_goadesign_goagen_service1_proto_goTypes = nil + file_goadesign_goagen_service1_proto_depIdxs = nil +} diff --git a/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.proto b/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.proto new file mode 100644 index 0000000..6c3ca5f --- /dev/null +++ b/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1.proto @@ -0,0 +1,42 @@ +// Code generated with goa v3.6.0, DO NOT EDIT. +// +// Service1 protocol buffer definition +// +// Command: +// $ goa gen goa_example/design + +syntax = "proto3"; + +package service1; + +option go_package = "/service1pb"; + +// The secured service exposes endpoints that require valid authorization +// credentials. +service Service1 { + // Signin implements signin. + rpc Signin (SigninRequest) returns (SigninResponse); + // 这是一个需要JWT认证的接口 + rpc Secure (SecureRequest) returns (SecureResponse); +} + +message SigninRequest { +} + +message SigninResponse { + // JWT token + string jwt = 1; + // API Key + string api_key = 2; + // OAuth2 token + string oauth_token = 3; +} + +message SecureRequest { + // Whether to force auth failure even with a valid JWT + bool fail = 1; +} + +message SecureResponse { + string field = 1; +} diff --git a/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1_grpc.pb.go b/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1_grpc.pb.go new file mode 100644 index 0000000..b996ba9 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/pb/goadesign_goagen_service1_grpc.pb.go @@ -0,0 +1,145 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.19.4 +// source: goadesign_goagen_service1.proto + +package service1pb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// Service1Client is the client API for Service1 service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type Service1Client interface { + // Signin implements signin. + Signin(ctx context.Context, in *SigninRequest, opts ...grpc.CallOption) (*SigninResponse, error) + // 这是一个需要JWT认证的接口 + Secure(ctx context.Context, in *SecureRequest, opts ...grpc.CallOption) (*SecureResponse, error) +} + +type service1Client struct { + cc grpc.ClientConnInterface +} + +func NewService1Client(cc grpc.ClientConnInterface) Service1Client { + return &service1Client{cc} +} + +func (c *service1Client) Signin(ctx context.Context, in *SigninRequest, opts ...grpc.CallOption) (*SigninResponse, error) { + out := new(SigninResponse) + err := c.cc.Invoke(ctx, "/service1.Service1/Signin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *service1Client) Secure(ctx context.Context, in *SecureRequest, opts ...grpc.CallOption) (*SecureResponse, error) { + out := new(SecureResponse) + err := c.cc.Invoke(ctx, "/service1.Service1/Secure", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Service1Server is the server API for Service1 service. +// All implementations must embed UnimplementedService1Server +// for forward compatibility +type Service1Server interface { + // Signin implements signin. + Signin(context.Context, *SigninRequest) (*SigninResponse, error) + // 这是一个需要JWT认证的接口 + Secure(context.Context, *SecureRequest) (*SecureResponse, error) + mustEmbedUnimplementedService1Server() +} + +// UnimplementedService1Server must be embedded to have forward compatible implementations. +type UnimplementedService1Server struct { +} + +func (UnimplementedService1Server) Signin(context.Context, *SigninRequest) (*SigninResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Signin not implemented") +} +func (UnimplementedService1Server) Secure(context.Context, *SecureRequest) (*SecureResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Secure not implemented") +} +func (UnimplementedService1Server) mustEmbedUnimplementedService1Server() {} + +// UnsafeService1Server may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to Service1Server will +// result in compilation errors. +type UnsafeService1Server interface { + mustEmbedUnimplementedService1Server() +} + +func RegisterService1Server(s grpc.ServiceRegistrar, srv Service1Server) { + s.RegisterService(&Service1_ServiceDesc, srv) +} + +func _Service1_Signin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SigninRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(Service1Server).Signin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/service1.Service1/Signin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(Service1Server).Signin(ctx, req.(*SigninRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Service1_Secure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SecureRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(Service1Server).Secure(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/service1.Service1/Secure", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(Service1Server).Secure(ctx, req.(*SecureRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Service1_ServiceDesc is the grpc.ServiceDesc for Service1 service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Service1_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "service1.Service1", + HandlerType: (*Service1Server)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Signin", + Handler: _Service1_Signin_Handler, + }, + { + MethodName: "Secure", + Handler: _Service1_Secure_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "goadesign_goagen_service1.proto", +} diff --git a/go/goa_example/gen/grpc/service1/server/encode_decode.go b/go/goa_example/gen/grpc/service1/server/encode_decode.go new file mode 100644 index 0000000..3337263 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/server/encode_decode.go @@ -0,0 +1,109 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC server encoders and decoders +// +// Command: +// $ goa gen goa_example/design + +package server + +import ( + "context" + service1pb "goa_example/gen/grpc/service1/pb" + service1 "goa_example/gen/service1" + "strings" + + goagrpc "goa.design/goa/v3/grpc" + goa "goa.design/goa/v3/pkg" + "google.golang.org/grpc/metadata" +) + +// EncodeSigninResponse encodes responses from the "Service1" service "signin" +// endpoint. +func EncodeSigninResponse(ctx context.Context, v interface{}, hdr, trlr *metadata.MD) (interface{}, error) { + result, ok := v.(*service1.Creds) + if !ok { + return nil, goagrpc.ErrInvalidType("Service1", "signin", "*service1.Creds", v) + } + resp := NewSigninResponse(result) + return resp, nil +} + +// DecodeSigninRequest decodes requests sent to "Service1" service "signin" +// endpoint. +func DecodeSigninRequest(ctx context.Context, v interface{}, md metadata.MD) (interface{}, error) { + var ( + username string + password string + err error + ) + { + if vals := md.Get("username"); len(vals) == 0 { + err = goa.MergeErrors(err, goa.MissingFieldError("username", "metadata")) + } else { + username = vals[0] + } + if vals := md.Get("password"); len(vals) == 0 { + err = goa.MergeErrors(err, goa.MissingFieldError("password", "metadata")) + } else { + password = vals[0] + } + } + if err != nil { + return nil, err + } + var payload *service1.SigninPayload + { + payload = NewSigninPayload(username, password) + } + return payload, nil +} + +// EncodeSecureResponse encodes responses from the "Service1" service "secure" +// endpoint. +func EncodeSecureResponse(ctx context.Context, v interface{}, hdr, trlr *metadata.MD) (interface{}, error) { + result, ok := v.(string) + if !ok { + return nil, goagrpc.ErrInvalidType("Service1", "secure", "string", v) + } + resp := NewSecureResponse(result) + return resp, nil +} + +// DecodeSecureRequest decodes requests sent to "Service1" service "secure" +// endpoint. +func DecodeSecureRequest(ctx context.Context, v interface{}, md metadata.MD) (interface{}, error) { + var ( + token string + err error + ) + { + if vals := md.Get("authorization"); len(vals) == 0 { + err = goa.MergeErrors(err, goa.MissingFieldError("authorization", "metadata")) + } else { + token = vals[0] + } + } + if err != nil { + return nil, err + } + var ( + message *service1pb.SecureRequest + ok bool + ) + { + if message, ok = v.(*service1pb.SecureRequest); !ok { + return nil, goagrpc.ErrInvalidType("Service1", "secure", "*service1pb.SecureRequest", v) + } + } + var payload *service1.SecurePayload + { + payload = NewSecurePayload(message, token) + if strings.Contains(payload.Token, " ") { + // Remove authorization scheme prefix (e.g. "Bearer") + cred := strings.SplitN(payload.Token, " ", 2)[1] + payload.Token = cred + } + } + return payload, nil +} diff --git a/go/goa_example/gen/grpc/service1/server/server.go b/go/goa_example/gen/grpc/service1/server/server.go new file mode 100644 index 0000000..11950a7 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/server/server.go @@ -0,0 +1,94 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC server +// +// Command: +// $ goa gen goa_example/design + +package server + +import ( + "context" + "errors" + service1pb "goa_example/gen/grpc/service1/pb" + service1 "goa_example/gen/service1" + + goagrpc "goa.design/goa/v3/grpc" + goa "goa.design/goa/v3/pkg" + "google.golang.org/grpc/codes" +) + +// Server implements the service1pb.Service1Server interface. +type Server struct { + SigninH goagrpc.UnaryHandler + SecureH goagrpc.UnaryHandler + service1pb.UnimplementedService1Server +} + +// ErrorNamer is an interface implemented by generated error structs that +// exposes the name of the error as defined in the expr. +type ErrorNamer interface { + ErrorName() string +} + +// New instantiates the server struct with the Service1 service endpoints. +func New(e *service1.Endpoints, uh goagrpc.UnaryHandler) *Server { + return &Server{ + SigninH: NewSigninHandler(e.Signin, uh), + SecureH: NewSecureHandler(e.Secure, uh), + } +} + +// NewSigninHandler creates a gRPC handler which serves the "Service1" service +// "signin" endpoint. +func NewSigninHandler(endpoint goa.Endpoint, h goagrpc.UnaryHandler) goagrpc.UnaryHandler { + if h == nil { + h = goagrpc.NewUnaryHandler(endpoint, DecodeSigninRequest, EncodeSigninResponse) + } + return h +} + +// Signin implements the "Signin" method in service1pb.Service1Server interface. +func (s *Server) Signin(ctx context.Context, message *service1pb.SigninRequest) (*service1pb.SigninResponse, error) { + ctx = context.WithValue(ctx, goa.MethodKey, "signin") + ctx = context.WithValue(ctx, goa.ServiceKey, "Service1") + resp, err := s.SigninH.Handle(ctx, message) + if err != nil { + var en ErrorNamer + if errors.As(err, &en) { + switch en.ErrorName() { + case "unauthorized": + return nil, goagrpc.NewStatusError(codes.Unauthenticated, err, goagrpc.NewErrorResponse(err)) + } + } + return nil, goagrpc.EncodeError(err) + } + return resp.(*service1pb.SigninResponse), nil +} + +// NewSecureHandler creates a gRPC handler which serves the "Service1" service +// "secure" endpoint. +func NewSecureHandler(endpoint goa.Endpoint, h goagrpc.UnaryHandler) goagrpc.UnaryHandler { + if h == nil { + h = goagrpc.NewUnaryHandler(endpoint, DecodeSecureRequest, EncodeSecureResponse) + } + return h +} + +// Secure implements the "Secure" method in service1pb.Service1Server interface. +func (s *Server) Secure(ctx context.Context, message *service1pb.SecureRequest) (*service1pb.SecureResponse, error) { + ctx = context.WithValue(ctx, goa.MethodKey, "secure") + ctx = context.WithValue(ctx, goa.ServiceKey, "Service1") + resp, err := s.SecureH.Handle(ctx, message) + if err != nil { + var en ErrorNamer + if errors.As(err, &en) { + switch en.ErrorName() { + case "unauthorized": + return nil, goagrpc.NewStatusError(codes.Unauthenticated, err, goagrpc.NewErrorResponse(err)) + } + } + return nil, goagrpc.EncodeError(err) + } + return resp.(*service1pb.SecureResponse), nil +} diff --git a/go/goa_example/gen/grpc/service1/server/types.go b/go/goa_example/gen/grpc/service1/server/types.go new file mode 100644 index 0000000..3249352 --- /dev/null +++ b/go/goa_example/gen/grpc/service1/server/types.go @@ -0,0 +1,51 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 gRPC server types +// +// Command: +// $ goa gen goa_example/design + +package server + +import ( + service1pb "goa_example/gen/grpc/service1/pb" + service1 "goa_example/gen/service1" +) + +// NewSigninPayload builds the payload of the "signin" endpoint of the +// "Service1" service from the gRPC request type. +func NewSigninPayload(username string, password string) *service1.SigninPayload { + v := &service1.SigninPayload{} + v.Username = username + v.Password = password + return v +} + +// NewSigninResponse builds the gRPC response type from the result of the +// "signin" endpoint of the "Service1" service. +func NewSigninResponse(result *service1.Creds) *service1pb.SigninResponse { + message := &service1pb.SigninResponse{ + Jwt: result.JWT, + ApiKey: result.APIKey, + OauthToken: result.OauthToken, + } + return message +} + +// NewSecurePayload builds the payload of the "secure" endpoint of the +// "Service1" service from the gRPC request type. +func NewSecurePayload(message *service1pb.SecureRequest, token string) *service1.SecurePayload { + v := &service1.SecurePayload{ + Fail: &message.Fail, + } + v.Token = token + return v +} + +// NewSecureResponse builds the gRPC response type from the result of the +// "secure" endpoint of the "Service1" service. +func NewSecureResponse(result string) *service1pb.SecureResponse { + message := &service1pb.SecureResponse{} + message.Field = result + return message +} diff --git a/go/goa_example/gen/http/cli/host/cli.go b/go/goa_example/gen/http/cli/host/cli.go new file mode 100644 index 0000000..827d691 --- /dev/null +++ b/go/goa_example/gen/http/cli/host/cli.go @@ -0,0 +1,179 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// host HTTP client CLI support package +// +// Command: +// $ goa gen goa_example/design + +package cli + +import ( + "flag" + "fmt" + service1c "goa_example/gen/http/service1/client" + "net/http" + "os" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// UsageCommands returns the set of commands and sub-commands using the format +// +// command (subcommand1|subcommand2|...) +// +func UsageCommands() string { + return `service1 (signin|secure) +` +} + +// UsageExamples produces an example of a valid invocation of the CLI tool. +func UsageExamples() string { + return os.Args[0] + ` service1 signin --username "user" --password "password"` + "\n" + + "" +} + +// ParseEndpoint returns the endpoint and payload as specified on the command +// line. +func ParseEndpoint( + scheme, host string, + doer goahttp.Doer, + enc func(*http.Request) goahttp.Encoder, + dec func(*http.Response) goahttp.Decoder, + restore bool, +) (goa.Endpoint, interface{}, error) { + var ( + service1Flags = flag.NewFlagSet("service1", flag.ContinueOnError) + + service1SigninFlags = flag.NewFlagSet("signin", flag.ExitOnError) + service1SigninUsernameFlag = service1SigninFlags.String("username", "REQUIRED", "Username used to perform signin") + service1SigninPasswordFlag = service1SigninFlags.String("password", "REQUIRED", "Password used to perform signin") + + service1SecureFlags = flag.NewFlagSet("secure", flag.ExitOnError) + service1SecureBodyFlag = service1SecureFlags.String("body", "REQUIRED", "") + service1SecureTokenFlag = service1SecureFlags.String("token", "REQUIRED", "") + ) + service1Flags.Usage = service1Usage + service1SigninFlags.Usage = service1SigninUsage + service1SecureFlags.Usage = service1SecureUsage + + if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { + return nil, nil, err + } + + if flag.NArg() < 2 { // two non flag args are required: SERVICE and ENDPOINT (aka COMMAND) + return nil, nil, fmt.Errorf("not enough arguments") + } + + var ( + svcn string + svcf *flag.FlagSet + ) + { + svcn = flag.Arg(0) + switch svcn { + case "service1": + svcf = service1Flags + default: + return nil, nil, fmt.Errorf("unknown service %q", svcn) + } + } + if err := svcf.Parse(flag.Args()[1:]); err != nil { + return nil, nil, err + } + + var ( + epn string + epf *flag.FlagSet + ) + { + epn = svcf.Arg(0) + switch svcn { + case "service1": + switch epn { + case "signin": + epf = service1SigninFlags + + case "secure": + epf = service1SecureFlags + + } + + } + } + if epf == nil { + return nil, nil, fmt.Errorf("unknown %q endpoint %q", svcn, epn) + } + + // Parse endpoint flags if any + if svcf.NArg() > 1 { + if err := epf.Parse(svcf.Args()[1:]); err != nil { + return nil, nil, err + } + } + + var ( + data interface{} + endpoint goa.Endpoint + err error + ) + { + switch svcn { + case "service1": + c := service1c.NewClient(scheme, host, doer, enc, dec, restore) + switch epn { + case "signin": + endpoint = c.Signin() + data, err = service1c.BuildSigninPayload(*service1SigninUsernameFlag, *service1SigninPasswordFlag) + case "secure": + endpoint = c.Secure() + data, err = service1c.BuildSecurePayload(*service1SecureBodyFlag, *service1SecureTokenFlag) + } + } + } + if err != nil { + return nil, nil, err + } + + return endpoint, data, nil +} + +// service1Usage displays the usage of the service1 command and its subcommands. +func service1Usage() { + fmt.Fprintf(os.Stderr, `The secured service exposes endpoints that require valid authorization credentials. +Usage: + %[1]s [globalflags] service1 COMMAND [flags] + +COMMAND: + signin: Signin implements signin. + secure: 这是一个需要JWT认证的接口 + +Additional help: + %[1]s service1 COMMAND --help +`, os.Args[0]) +} +func service1SigninUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] service1 signin -username STRING -password STRING + +Signin implements signin. + -username STRING: Username used to perform signin + -password STRING: Password used to perform signin + +Example: + %[1]s service1 signin --username "user" --password "password" +`, os.Args[0]) +} + +func service1SecureUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] service1 secure -body JSON -token STRING + +这是一个需要JWT认证的接口 + -body JSON: + -token STRING: + +Example: + %[1]s service1 secure --body '{ + "fail": true + }' --token "Ducimus aut similique." +`, os.Args[0]) +} diff --git a/go/goa_example/gen/http/openapi.json b/go/goa_example/gen/http/openapi.json new file mode 100644 index 0000000..2027dc4 --- /dev/null +++ b/go/goa_example/gen/http/openapi.json @@ -0,0 +1 @@ +{"swagger":"2.0","info":{"title":"A Goa Example Service","description":"HTTP service for test","version":""},"host":"localhost:8088","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/secure":{"get":{"tags":["Service1"],"summary":"secure Service1","description":"这是一个需要JWT认证的接口","operationId":"Service1#secure","parameters":[{"name":"Authorization","in":"header","description":"JWT used for authentication","required":true,"type":"string"},{"name":"SecureRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/Service1SecureRequestBody"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string"}},"401":{"description":"Unauthorized response.","schema":{"type":"string"}}},"schemes":["http"],"security":[{"jwt_header_Authorization":[]}]}},"/signin":{"post":{"tags":["Service1"],"summary":"signin Service1","operationId":"Service1#signin","parameters":[{"name":"Authorization","in":"header","description":"Basic Auth security using Basic scheme (https://tools.ietf.org/html/rfc7617)","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/Service1SigninOKResponseBody","required":["jwt","api_key","oauth_token"]}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/Service1SigninBadRequestResponseBody","required":["jwt","api_key","oauth_token"]}},"401":{"description":"Unauthorized response.","schema":{"type":"string"}}},"schemes":["http"],"security":[{"basic_header_Authorization":[]}]}}},"definitions":{"Service1SecureRequestBody":{"title":"Service1SecureRequestBody","type":"object","properties":{"fail":{"type":"boolean","description":"Whether to force auth failure even with a valid JWT","example":false}},"example":{"fail":false}},"Service1SigninBadRequestResponseBody":{"title":"Service1SigninBadRequestResponseBody","type":"object","properties":{"api_key":{"type":"string","description":"API Key","example":"abcdef12345"},"jwt":{"type":"string","description":"JWT token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"},"oauth_token":{"type":"string","description":"OAuth2 token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"}},"example":{"api_key":"abcdef12345","jwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ","oauth_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"},"required":["jwt","api_key","oauth_token"]},"Service1SigninOKResponseBody":{"title":"Service1SigninOKResponseBody","type":"object","properties":{"api_key":{"type":"string","description":"API Key","example":"abcdef12345"},"jwt":{"type":"string","description":"JWT token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"},"oauth_token":{"type":"string","description":"OAuth2 token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"}},"example":{"api_key":"abcdef12345","jwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ","oauth_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"},"required":["jwt","api_key","oauth_token"]}},"securityDefinitions":{"basic_header_Authorization":{"type":"basic","description":"Basic authentication used to authenticate security principal during signin"},"jwt_header_Authorization":{"type":"apiKey","description":"Secures endpoint by requiring a valid JWT token retrieved via the signin endpoint. Supports scopes \"api:read\" and \"api:write\".","name":"Authorization","in":"header"}}} \ No newline at end of file diff --git a/go/goa_example/gen/http/openapi.yaml b/go/goa_example/gen/http/openapi.yaml new file mode 100644 index 0000000..e94b666 --- /dev/null +++ b/go/goa_example/gen/http/openapi.yaml @@ -0,0 +1,153 @@ +swagger: "2.0" +info: + title: A Goa Example Service + description: HTTP service for test + version: "" +host: localhost:8088 +consumes: +- application/json +- application/xml +- application/gob +produces: +- application/json +- application/xml +- application/gob +paths: + /secure: + get: + tags: + - Service1 + summary: secure Service1 + description: 这是一个需要JWT认证的接口 + operationId: Service1#secure + parameters: + - name: Authorization + in: header + description: JWT used for authentication + required: true + type: string + - name: SecureRequestBody + in: body + required: true + schema: + $ref: '#/definitions/Service1SecureRequestBody' + responses: + "200": + description: OK response. + schema: + type: string + "401": + description: Unauthorized response. + schema: + type: string + schemes: + - http + security: + - jwt_header_Authorization: [] + /signin: + post: + tags: + - Service1 + summary: signin Service1 + operationId: Service1#signin + parameters: + - name: Authorization + in: header + description: Basic Auth security using Basic scheme (https://tools.ietf.org/html/rfc7617) + required: true + type: string + responses: + "200": + description: OK response. + schema: + $ref: '#/definitions/Service1SigninOKResponseBody' + required: + - jwt + - api_key + - oauth_token + "400": + description: Bad Request response. + schema: + $ref: '#/definitions/Service1SigninBadRequestResponseBody' + required: + - jwt + - api_key + - oauth_token + "401": + description: Unauthorized response. + schema: + type: string + schemes: + - http + security: + - basic_header_Authorization: [] +definitions: + Service1SecureRequestBody: + title: Service1SecureRequestBody + type: object + properties: + fail: + type: boolean + description: Whether to force auth failure even with a valid JWT + example: false + example: + fail: false + Service1SigninBadRequestResponseBody: + title: Service1SigninBadRequestResponseBody + type: object + properties: + api_key: + type: string + description: API Key + example: abcdef12345 + jwt: + type: string + description: JWT token + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: + type: string + description: OAuth2 token + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + example: + api_key: abcdef12345 + jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + required: + - jwt + - api_key + - oauth_token + Service1SigninOKResponseBody: + title: Service1SigninOKResponseBody + type: object + properties: + api_key: + type: string + description: API Key + example: abcdef12345 + jwt: + type: string + description: JWT token + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: + type: string + description: OAuth2 token + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + example: + api_key: abcdef12345 + jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + required: + - jwt + - api_key + - oauth_token +securityDefinitions: + basic_header_Authorization: + type: basic + description: Basic authentication used to authenticate security principal during + signin + jwt_header_Authorization: + type: apiKey + description: Secures endpoint by requiring a valid JWT token retrieved via the + signin endpoint. Supports scopes "api:read" and "api:write". + name: Authorization + in: header diff --git a/go/goa_example/gen/http/openapi3.json b/go/goa_example/gen/http/openapi3.json new file mode 100644 index 0000000..e40903f --- /dev/null +++ b/go/goa_example/gen/http/openapi3.json @@ -0,0 +1 @@ +{"openapi":"3.0.3","info":{"title":"A Goa Example Service","description":"HTTP service for test","version":"1.0"},"servers":[{"url":"http://localhost:8088"},{"url":"http://localhost:8088"}],"paths":{"/secure":{"get":{"tags":["Service1"],"summary":"secure Service1","description":"这是一个需要JWT认证的接口","operationId":"Service1#secure","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecureRequestBody"},"example":{"fail":true}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Commodi earum ut dolorem qui."},"example":"Aliquid corrupti facere voluptate."}}},"401":{"description":"Unauthorized response.","content":{"application/json":{"schema":{"type":"string","example":"Alias placeat est tenetur ad distinctio nesciunt."},"example":"Odit qui ut culpa est."}}}},"security":[{"jwt_header_Authorization":[]}]}},"/signin":{"post":{"tags":["Service1"],"summary":"signin Service1","operationId":"Service1#signin","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Creds"},"example":{"api_key":"abcdef12345","jwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ","oauth_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"}}}},"400":{"description":"Bad Request response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Creds"},"example":{"api_key":"abcdef12345","jwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ","oauth_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"}}}},"401":{"description":"Unauthorized response.","content":{"application/json":{"schema":{"type":"string","example":"Voluptate non dolore autem ipsam omnis."},"example":"Et necessitatibus cupiditate repudiandae iste."}}}},"security":[{"basic_header_Authorization":[]}]}}},"components":{"schemas":{"Creds":{"type":"object","properties":{"api_key":{"type":"string","description":"API Key","example":"abcdef12345"},"jwt":{"type":"string","description":"JWT token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"},"oauth_token":{"type":"string","description":"OAuth2 token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"}},"example":{"api_key":"abcdef12345","jwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ","oauth_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"},"required":["jwt","api_key","oauth_token"]},"SecureRequestBody":{"type":"object","properties":{"fail":{"type":"boolean","description":"Whether to force auth failure even with a valid JWT","example":false}},"example":{"fail":false}}},"securitySchemes":{"basic_header_Authorization":{"type":"http","description":"Basic authentication used to authenticate security principal during signin","scheme":"basic"},"jwt_header_Authorization":{"type":"http","description":"Secures endpoint by requiring a valid JWT token retrieved via the signin endpoint. Supports scopes \"api:read\" and \"api:write\".","scheme":"bearer"}}},"tags":[{"name":"Service1","description":"The secured service exposes endpoints that require valid authorization credentials."}]} \ No newline at end of file diff --git a/go/goa_example/gen/http/openapi3.yaml b/go/goa_example/gen/http/openapi3.yaml new file mode 100644 index 0000000..b19ea30 --- /dev/null +++ b/go/goa_example/gen/http/openapi3.yaml @@ -0,0 +1,129 @@ +openapi: 3.0.3 +info: + title: A Goa Example Service + description: HTTP service for test + version: "1.0" +servers: +- url: http://localhost:8088 +- url: http://localhost:8088 +paths: + /secure: + get: + tags: + - Service1 + summary: secure Service1 + description: 这是一个需要JWT认证的接口 + operationId: Service1#secure + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SecureRequestBody' + example: + fail: true + responses: + "200": + description: OK response. + content: + application/json: + schema: + type: string + example: Commodi earum ut dolorem qui. + example: Aliquid corrupti facere voluptate. + "401": + description: Unauthorized response. + content: + application/json: + schema: + type: string + example: Alias placeat est tenetur ad distinctio nesciunt. + example: Odit qui ut culpa est. + security: + - jwt_header_Authorization: [] + /signin: + post: + tags: + - Service1 + summary: signin Service1 + operationId: Service1#signin + responses: + "200": + description: OK response. + content: + application/json: + schema: + $ref: '#/components/schemas/Creds' + example: + api_key: abcdef12345 + jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + "400": + description: Bad Request response. + content: + application/json: + schema: + $ref: '#/components/schemas/Creds' + example: + api_key: abcdef12345 + jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + "401": + description: Unauthorized response. + content: + application/json: + schema: + type: string + example: Voluptate non dolore autem ipsam omnis. + example: Et necessitatibus cupiditate repudiandae iste. + security: + - basic_header_Authorization: [] +components: + schemas: + Creds: + type: object + properties: + api_key: + type: string + description: API Key + example: abcdef12345 + jwt: + type: string + description: JWT token + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: + type: string + description: OAuth2 token + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + example: + api_key: abcdef12345 + jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + oauth_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ + required: + - jwt + - api_key + - oauth_token + SecureRequestBody: + type: object + properties: + fail: + type: boolean + description: Whether to force auth failure even with a valid JWT + example: false + example: + fail: false + securitySchemes: + basic_header_Authorization: + type: http + description: Basic authentication used to authenticate security principal during + signin + scheme: basic + jwt_header_Authorization: + type: http + description: Secures endpoint by requiring a valid JWT token retrieved via the + signin endpoint. Supports scopes "api:read" and "api:write". + scheme: bearer +tags: +- name: Service1 + description: The secured service exposes endpoints that require valid authorization + credentials. diff --git a/go/goa_example/gen/http/service1/client/cli.go b/go/goa_example/gen/http/service1/client/cli.go new file mode 100644 index 0000000..b0dbfa3 --- /dev/null +++ b/go/goa_example/gen/http/service1/client/cli.go @@ -0,0 +1,55 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 HTTP client CLI support package +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + "encoding/json" + "fmt" + service1 "goa_example/gen/service1" +) + +// BuildSigninPayload builds the payload for the Service1 signin endpoint from +// CLI flags. +func BuildSigninPayload(service1SigninUsername string, service1SigninPassword string) (*service1.SigninPayload, error) { + var username string + { + username = service1SigninUsername + } + var password string + { + password = service1SigninPassword + } + v := &service1.SigninPayload{} + v.Username = username + v.Password = password + + return v, nil +} + +// BuildSecurePayload builds the payload for the Service1 secure endpoint from +// CLI flags. +func BuildSecurePayload(service1SecureBody string, service1SecureToken string) (*service1.SecurePayload, error) { + var err error + var body SecureRequestBody + { + err = json.Unmarshal([]byte(service1SecureBody), &body) + if err != nil { + return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"fail\": true\n }'") + } + } + var token string + { + token = service1SecureToken + } + v := &service1.SecurePayload{ + Fail: body.Fail, + } + v.Token = token + + return v, nil +} diff --git a/go/goa_example/gen/http/service1/client/client.go b/go/goa_example/gen/http/service1/client/client.go new file mode 100644 index 0000000..fa0c375 --- /dev/null +++ b/go/goa_example/gen/http/service1/client/client.go @@ -0,0 +1,102 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 client HTTP transport +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + "context" + "net/http" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// Client lists the Service1 service endpoint HTTP clients. +type Client struct { + // Signin Doer is the HTTP client used to make requests to the signin endpoint. + SigninDoer goahttp.Doer + + // Secure Doer is the HTTP client used to make requests to the secure endpoint. + SecureDoer goahttp.Doer + + // RestoreResponseBody controls whether the response bodies are reset after + // decoding so they can be read again. + RestoreResponseBody bool + + scheme string + host string + encoder func(*http.Request) goahttp.Encoder + decoder func(*http.Response) goahttp.Decoder +} + +// NewClient instantiates HTTP clients for all the Service1 service servers. +func NewClient( + scheme string, + host string, + doer goahttp.Doer, + enc func(*http.Request) goahttp.Encoder, + dec func(*http.Response) goahttp.Decoder, + restoreBody bool, +) *Client { + return &Client{ + SigninDoer: doer, + SecureDoer: doer, + RestoreResponseBody: restoreBody, + scheme: scheme, + host: host, + decoder: dec, + encoder: enc, + } +} + +// Signin returns an endpoint that makes HTTP requests to the Service1 service +// signin server. +func (c *Client) Signin() goa.Endpoint { + var ( + encodeRequest = EncodeSigninRequest(c.encoder) + decodeResponse = DecodeSigninResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v interface{}) (interface{}, error) { + req, err := c.BuildSigninRequest(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.SigninDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("Service1", "signin", err) + } + return decodeResponse(resp) + } +} + +// Secure returns an endpoint that makes HTTP requests to the Service1 service +// secure server. +func (c *Client) Secure() goa.Endpoint { + var ( + encodeRequest = EncodeSecureRequest(c.encoder) + decodeResponse = DecodeSecureResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v interface{}) (interface{}, error) { + req, err := c.BuildSecureRequest(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.SecureDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("Service1", "secure", err) + } + return decodeResponse(resp) + } +} diff --git a/go/goa_example/gen/http/service1/client/encode_decode.go b/go/goa_example/gen/http/service1/client/encode_decode.go new file mode 100644 index 0000000..0525010 --- /dev/null +++ b/go/goa_example/gen/http/service1/client/encode_decode.go @@ -0,0 +1,188 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 HTTP client encoders and decoders +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + "bytes" + "context" + service1 "goa_example/gen/service1" + "io/ioutil" + "net/http" + "net/url" + "strings" + + goahttp "goa.design/goa/v3/http" +) + +// BuildSigninRequest instantiates a HTTP request object with method and path +// set to call the "Service1" service "signin" endpoint +func (c *Client) BuildSigninRequest(ctx context.Context, v interface{}) (*http.Request, error) { + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: SigninService1Path()} + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("Service1", "signin", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodeSigninRequest returns an encoder for requests sent to the Service1 +// signin server. +func EncodeSigninRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error { + return func(req *http.Request, v interface{}) error { + p, ok := v.(*service1.SigninPayload) + if !ok { + return goahttp.ErrInvalidType("Service1", "signin", "*service1.SigninPayload", v) + } + req.SetBasicAuth(p.Username, p.Password) + return nil + } +} + +// DecodeSigninResponse returns a decoder for responses returned by the +// Service1 signin endpoint. restoreBody controls whether the response body +// should be restored after having been read. +// DecodeSigninResponse may return the following errors: +// - "unauthorized" (type service1.Unauthorized): http.StatusUnauthorized +// - error: internal error +func DecodeSigninResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { + return func(resp *http.Response) (interface{}, error) { + if restoreBody { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body SigninOKResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("Service1", "signin", err) + } + err = ValidateSigninOKResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("Service1", "signin", err) + } + res := NewSigninCredsOK(&body) + return res, nil + case http.StatusUnauthorized: + var ( + body string + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("Service1", "signin", err) + } + return nil, NewSigninUnauthorized(body) + default: + body, _ := ioutil.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("Service1", "signin", resp.StatusCode, string(body)) + } + } +} + +// BuildSecureRequest instantiates a HTTP request object with method and path +// set to call the "Service1" service "secure" endpoint +func (c *Client) BuildSecureRequest(ctx context.Context, v interface{}) (*http.Request, error) { + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: SecureService1Path()} + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("Service1", "secure", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodeSecureRequest returns an encoder for requests sent to the Service1 +// secure server. +func EncodeSecureRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error { + return func(req *http.Request, v interface{}) error { + p, ok := v.(*service1.SecurePayload) + if !ok { + return goahttp.ErrInvalidType("Service1", "secure", "*service1.SecurePayload", v) + } + { + head := p.Token + if !strings.Contains(head, " ") { + req.Header.Set("Authorization", "Bearer "+head) + } else { + req.Header.Set("Authorization", head) + } + } + body := NewSecureRequestBody(p) + if err := encoder(req).Encode(&body); err != nil { + return goahttp.ErrEncodingError("Service1", "secure", err) + } + return nil + } +} + +// DecodeSecureResponse returns a decoder for responses returned by the +// Service1 secure endpoint. restoreBody controls whether the response body +// should be restored after having been read. +// DecodeSecureResponse may return the following errors: +// - "unauthorized" (type service1.Unauthorized): http.StatusUnauthorized +// - error: internal error +func DecodeSecureResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { + return func(resp *http.Response) (interface{}, error) { + if restoreBody { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body string + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("Service1", "secure", err) + } + return body, nil + case http.StatusUnauthorized: + var ( + body string + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("Service1", "secure", err) + } + return nil, NewSecureUnauthorized(body) + default: + body, _ := ioutil.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("Service1", "secure", resp.StatusCode, string(body)) + } + } +} diff --git a/go/goa_example/gen/http/service1/client/paths.go b/go/goa_example/gen/http/service1/client/paths.go new file mode 100644 index 0000000..50cf606 --- /dev/null +++ b/go/goa_example/gen/http/service1/client/paths.go @@ -0,0 +1,18 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// HTTP request path constructors for the Service1 service. +// +// Command: +// $ goa gen goa_example/design + +package client + +// SigninService1Path returns the URL path to the Service1 service signin HTTP endpoint. +func SigninService1Path() string { + return "/signin" +} + +// SecureService1Path returns the URL path to the Service1 service secure HTTP endpoint. +func SecureService1Path() string { + return "/secure" +} diff --git a/go/goa_example/gen/http/service1/client/types.go b/go/goa_example/gen/http/service1/client/types.go new file mode 100644 index 0000000..3df45f8 --- /dev/null +++ b/go/goa_example/gen/http/service1/client/types.go @@ -0,0 +1,109 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 HTTP client types +// +// Command: +// $ goa gen goa_example/design + +package client + +import ( + service1 "goa_example/gen/service1" + + goa "goa.design/goa/v3/pkg" +) + +// SecureRequestBody is the type of the "Service1" service "secure" endpoint +// HTTP request body. +type SecureRequestBody struct { + // Whether to force auth failure even with a valid JWT + Fail *bool `form:"fail,omitempty" json:"fail,omitempty" xml:"fail,omitempty"` +} + +// SigninOKResponseBody is the type of the "Service1" service "signin" endpoint +// HTTP response body. +type SigninOKResponseBody struct { + // JWT token + JWT *string `form:"jwt,omitempty" json:"jwt,omitempty" xml:"jwt,omitempty"` + // API Key + APIKey *string `form:"api_key,omitempty" json:"api_key,omitempty" xml:"api_key,omitempty"` + // OAuth2 token + OauthToken *string `form:"oauth_token,omitempty" json:"oauth_token,omitempty" xml:"oauth_token,omitempty"` +} + +// SigninBadRequestResponseBody is used to define fields on response body types. +type SigninBadRequestResponseBody struct { + // JWT token + JWT *string `form:"jwt,omitempty" json:"jwt,omitempty" xml:"jwt,omitempty"` + // API Key + APIKey *string `form:"api_key,omitempty" json:"api_key,omitempty" xml:"api_key,omitempty"` + // OAuth2 token + OauthToken *string `form:"oauth_token,omitempty" json:"oauth_token,omitempty" xml:"oauth_token,omitempty"` +} + +// NewSecureRequestBody builds the HTTP request body from the payload of the +// "secure" endpoint of the "Service1" service. +func NewSecureRequestBody(p *service1.SecurePayload) *SecureRequestBody { + body := &SecureRequestBody{ + Fail: p.Fail, + } + return body +} + +// NewSigninCredsOK builds a "Service1" service "signin" endpoint result from a +// HTTP "OK" response. +func NewSigninCredsOK(body *SigninOKResponseBody) *service1.Creds { + v := &service1.Creds{ + JWT: *body.JWT, + APIKey: *body.APIKey, + OauthToken: *body.OauthToken, + } + + return v +} + +// NewSigninUnauthorized builds a Service1 service signin endpoint unauthorized +// error. +func NewSigninUnauthorized(body string) service1.Unauthorized { + v := service1.Unauthorized(body) + + return v +} + +// NewSecureUnauthorized builds a Service1 service secure endpoint unauthorized +// error. +func NewSecureUnauthorized(body string) service1.Unauthorized { + v := service1.Unauthorized(body) + + return v +} + +// ValidateSigninOKResponseBody runs the validations defined on +// SigninOKResponseBody +func ValidateSigninOKResponseBody(body *SigninOKResponseBody) (err error) { + if body.JWT == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("jwt", "body")) + } + if body.APIKey == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("api_key", "body")) + } + if body.OauthToken == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("oauth_token", "body")) + } + return +} + +// ValidateSigninBadRequestResponseBody runs the validations defined on +// SigninBad RequestResponseBody +func ValidateSigninBadRequestResponseBody(body *SigninBadRequestResponseBody) (err error) { + if body.JWT == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("jwt", "body")) + } + if body.APIKey == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("api_key", "body")) + } + if body.OauthToken == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("oauth_token", "body")) + } + return +} diff --git a/go/goa_example/gen/http/service1/server/encode_decode.go b/go/goa_example/gen/http/service1/server/encode_decode.go new file mode 100644 index 0000000..423d69d --- /dev/null +++ b/go/goa_example/gen/http/service1/server/encode_decode.go @@ -0,0 +1,143 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 HTTP server encoders and decoders +// +// Command: +// $ goa gen goa_example/design + +package server + +import ( + "context" + "errors" + service1 "goa_example/gen/service1" + "io" + "net/http" + "strings" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// EncodeSigninResponse returns an encoder for responses returned by the +// Service1 signin endpoint. +func EncodeSigninResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { + return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { + res, _ := v.(*service1.Creds) + enc := encoder(ctx, w) + body := NewSigninOKResponseBody(res) + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeSigninRequest returns a decoder for requests sent to the Service1 +// signin endpoint. +func DecodeSigninRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { + return func(r *http.Request) (interface{}, error) { + payload := NewSigninPayload() + user, pass, ok := r.BasicAuth() + if !ok { + return nil, goa.MissingFieldError("Authorization", "header") + } + payload.Username = user + payload.Password = pass + + return payload, nil + } +} + +// EncodeSigninError returns an encoder for errors returned by the signin +// Service1 endpoint. +func EncodeSigninError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error { + encodeError := goahttp.ErrorEncoder(encoder, formatter) + return func(ctx context.Context, w http.ResponseWriter, v error) error { + var en ErrorNamer + if !errors.As(v, &en) { + return encodeError(ctx, w, v) + } + switch en.ErrorName() { + case "unauthorized": + res := v.(service1.Unauthorized) + enc := encoder(ctx, w) + body := res + w.Header().Set("goa-error", res.ErrorName()) + w.WriteHeader(http.StatusUnauthorized) + return enc.Encode(body) + default: + return encodeError(ctx, w, v) + } + } +} + +// EncodeSecureResponse returns an encoder for responses returned by the +// Service1 secure endpoint. +func EncodeSecureResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { + return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { + res, _ := v.(string) + enc := encoder(ctx, w) + body := res + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeSecureRequest returns a decoder for requests sent to the Service1 +// secure endpoint. +func DecodeSecureRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { + return func(r *http.Request) (interface{}, error) { + var ( + body SecureRequestBody + err error + ) + err = decoder(r).Decode(&body) + if err != nil { + if err == io.EOF { + return nil, goa.MissingPayloadError() + } + return nil, goa.DecodePayloadError(err.Error()) + } + + var ( + token string + ) + token = r.Header.Get("Authorization") + if token == "" { + err = goa.MergeErrors(err, goa.MissingFieldError("Authorization", "header")) + } + if err != nil { + return nil, err + } + payload := NewSecurePayload(&body, token) + if strings.Contains(payload.Token, " ") { + // Remove authorization scheme prefix (e.g. "Bearer") + cred := strings.SplitN(payload.Token, " ", 2)[1] + payload.Token = cred + } + + return payload, nil + } +} + +// EncodeSecureError returns an encoder for errors returned by the secure +// Service1 endpoint. +func EncodeSecureError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error { + encodeError := goahttp.ErrorEncoder(encoder, formatter) + return func(ctx context.Context, w http.ResponseWriter, v error) error { + var en ErrorNamer + if !errors.As(v, &en) { + return encodeError(ctx, w, v) + } + switch en.ErrorName() { + case "unauthorized": + res := v.(service1.Unauthorized) + enc := encoder(ctx, w) + body := res + w.Header().Set("goa-error", res.ErrorName()) + w.WriteHeader(http.StatusUnauthorized) + return enc.Encode(body) + default: + return encodeError(ctx, w, v) + } + } +} diff --git a/go/goa_example/gen/http/service1/server/paths.go b/go/goa_example/gen/http/service1/server/paths.go new file mode 100644 index 0000000..5fe63eb --- /dev/null +++ b/go/goa_example/gen/http/service1/server/paths.go @@ -0,0 +1,18 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// HTTP request path constructors for the Service1 service. +// +// Command: +// $ goa gen goa_example/design + +package server + +// SigninService1Path returns the URL path to the Service1 service signin HTTP endpoint. +func SigninService1Path() string { + return "/signin" +} + +// SecureService1Path returns the URL path to the Service1 service secure HTTP endpoint. +func SecureService1Path() string { + return "/secure" +} diff --git a/go/goa_example/gen/http/service1/server/server.go b/go/goa_example/gen/http/service1/server/server.go new file mode 100644 index 0000000..a0bb143 --- /dev/null +++ b/go/goa_example/gen/http/service1/server/server.go @@ -0,0 +1,187 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 HTTP server +// +// Command: +// $ goa gen goa_example/design + +package server + +import ( + "context" + service1 "goa_example/gen/service1" + "net/http" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// Server lists the Service1 service endpoint HTTP handlers. +type Server struct { + Mounts []*MountPoint + Signin http.Handler + Secure http.Handler +} + +// ErrorNamer is an interface implemented by generated error structs that +// exposes the name of the error as defined in the design. +type ErrorNamer interface { + ErrorName() string +} + +// MountPoint holds information about the mounted endpoints. +type MountPoint struct { + // Method is the name of the service method served by the mounted HTTP handler. + Method string + // Verb is the HTTP method used to match requests to the mounted handler. + Verb string + // Pattern is the HTTP request path pattern used to match requests to the + // mounted handler. + Pattern string +} + +// New instantiates HTTP handlers for all the Service1 service endpoints using +// the provided encoder and decoder. The handlers are mounted on the given mux +// using the HTTP verb and path defined in the design. errhandler is called +// whenever a response fails to be encoded. formatter is used to format errors +// returned by the service methods prior to encoding. Both errhandler and +// formatter are optional and can be nil. +func New( + e *service1.Endpoints, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(err error) goahttp.Statuser, +) *Server { + return &Server{ + Mounts: []*MountPoint{ + {"Signin", "POST", "/signin"}, + {"Secure", "GET", "/secure"}, + }, + Signin: NewSigninHandler(e.Signin, mux, decoder, encoder, errhandler, formatter), + Secure: NewSecureHandler(e.Secure, mux, decoder, encoder, errhandler, formatter), + } +} + +// Service returns the name of the service served. +func (s *Server) Service() string { return "Service1" } + +// Use wraps the server handlers with the given middleware. +func (s *Server) Use(m func(http.Handler) http.Handler) { + s.Signin = m(s.Signin) + s.Secure = m(s.Secure) +} + +// Mount configures the mux to serve the Service1 endpoints. +func Mount(mux goahttp.Muxer, h *Server) { + MountSigninHandler(mux, h.Signin) + MountSecureHandler(mux, h.Secure) +} + +// Mount configures the mux to serve the Service1 endpoints. +func (s *Server) Mount(mux goahttp.Muxer) { + Mount(mux, s) +} + +// MountSigninHandler configures the mux to serve the "Service1" service +// "signin" endpoint. +func MountSigninHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("POST", "/signin", f) +} + +// NewSigninHandler creates a HTTP handler which loads the HTTP request and +// calls the "Service1" service "signin" endpoint. +func NewSigninHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeSigninRequest(mux, decoder) + encodeResponse = EncodeSigninResponse(encoder) + encodeError = EncodeSigninError(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "signin") + ctx = context.WithValue(ctx, goa.ServiceKey, "Service1") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + errhandler(ctx, w, err) + } + }) +} + +// MountSecureHandler configures the mux to serve the "Service1" service +// "secure" endpoint. +func MountSecureHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("GET", "/secure", f) +} + +// NewSecureHandler creates a HTTP handler which loads the HTTP request and +// calls the "Service1" service "secure" endpoint. +func NewSecureHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeSecureRequest(mux, decoder) + encodeResponse = EncodeSecureResponse(encoder) + encodeError = EncodeSecureError(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "secure") + ctx = context.WithValue(ctx, goa.ServiceKey, "Service1") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + errhandler(ctx, w, err) + } + }) +} diff --git a/go/goa_example/gen/http/service1/server/types.go b/go/goa_example/gen/http/service1/server/types.go new file mode 100644 index 0000000..ff53dea --- /dev/null +++ b/go/goa_example/gen/http/service1/server/types.go @@ -0,0 +1,58 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 HTTP server types +// +// Command: +// $ goa gen goa_example/design + +package server + +import ( + service1 "goa_example/gen/service1" +) + +// SecureRequestBody is the type of the "Service1" service "secure" endpoint +// HTTP request body. +type SecureRequestBody struct { + // Whether to force auth failure even with a valid JWT + Fail *bool `form:"fail,omitempty" json:"fail,omitempty" xml:"fail,omitempty"` +} + +// SigninOKResponseBody is the type of the "Service1" service "signin" endpoint +// HTTP response body. +type SigninOKResponseBody struct { + // JWT token + JWT string `form:"jwt" json:"jwt" xml:"jwt"` + // API Key + APIKey string `form:"api_key" json:"api_key" xml:"api_key"` + // OAuth2 token + OauthToken string `form:"oauth_token" json:"oauth_token" xml:"oauth_token"` +} + +// NewSigninOKResponseBody builds the HTTP response body from the result of the +// "signin" endpoint of the "Service1" service. +func NewSigninOKResponseBody(res *service1.Creds) *SigninOKResponseBody { + body := &SigninOKResponseBody{ + JWT: res.JWT, + APIKey: res.APIKey, + OauthToken: res.OauthToken, + } + return body +} + +// NewSigninPayload builds a Service1 service signin endpoint payload. +func NewSigninPayload() *service1.SigninPayload { + v := &service1.SigninPayload{} + + return v +} + +// NewSecurePayload builds a Service1 service secure endpoint payload. +func NewSecurePayload(body *SecureRequestBody, token string) *service1.SecurePayload { + v := &service1.SecurePayload{ + Fail: body.Fail, + } + v.Token = token + + return v +} diff --git a/go/goa_example/gen/service1/client.go b/go/goa_example/gen/service1/client.go new file mode 100644 index 0000000..9217539 --- /dev/null +++ b/go/goa_example/gen/service1/client.go @@ -0,0 +1,48 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 client +// +// Command: +// $ goa gen goa_example/design + +package service1 + +import ( + "context" + + goa "goa.design/goa/v3/pkg" +) + +// Client is the "Service1" service client. +type Client struct { + SigninEndpoint goa.Endpoint + SecureEndpoint goa.Endpoint +} + +// NewClient initializes a "Service1" service client given the endpoints. +func NewClient(signin, secure goa.Endpoint) *Client { + return &Client{ + SigninEndpoint: signin, + SecureEndpoint: secure, + } +} + +// Signin calls the "signin" endpoint of the "Service1" service. +func (c *Client) Signin(ctx context.Context, p *SigninPayload) (res *Creds, err error) { + var ires interface{} + ires, err = c.SigninEndpoint(ctx, p) + if err != nil { + return + } + return ires.(*Creds), nil +} + +// Secure calls the "secure" endpoint of the "Service1" service. +func (c *Client) Secure(ctx context.Context, p *SecurePayload) (res string, err error) { + var ires interface{} + ires, err = c.SecureEndpoint(ctx, p) + if err != nil { + return + } + return ires.(string), nil +} diff --git a/go/goa_example/gen/service1/endpoints.go b/go/goa_example/gen/service1/endpoints.go new file mode 100644 index 0000000..192841d --- /dev/null +++ b/go/goa_example/gen/service1/endpoints.go @@ -0,0 +1,75 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 endpoints +// +// Command: +// $ goa gen goa_example/design + +package service1 + +import ( + "context" + + goa "goa.design/goa/v3/pkg" + "goa.design/goa/v3/security" +) + +// Endpoints wraps the "Service1" service endpoints. +type Endpoints struct { + Signin goa.Endpoint + Secure goa.Endpoint +} + +// NewEndpoints wraps the methods of the "Service1" service with endpoints. +func NewEndpoints(s Service) *Endpoints { + // Casting service to Auther interface + a := s.(Auther) + return &Endpoints{ + Signin: NewSigninEndpoint(s, a.BasicAuth), + Secure: NewSecureEndpoint(s, a.JWTAuth), + } +} + +// Use applies the given middleware to all the "Service1" service endpoints. +func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { + e.Signin = m(e.Signin) + e.Secure = m(e.Secure) +} + +// NewSigninEndpoint returns an endpoint function that calls the method +// "signin" of service "Service1". +func NewSigninEndpoint(s Service, authBasicFn security.AuthBasicFunc) goa.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + p := req.(*SigninPayload) + var err error + sc := security.BasicScheme{ + Name: "basic", + Scopes: []string{}, + RequiredScopes: []string{}, + } + ctx, err = authBasicFn(ctx, p.Username, p.Password, &sc) + if err != nil { + return nil, err + } + return s.Signin(ctx, p) + } +} + +// NewSecureEndpoint returns an endpoint function that calls the method +// "secure" of service "Service1". +func NewSecureEndpoint(s Service, authJWTFn security.AuthJWTFunc) goa.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + p := req.(*SecurePayload) + var err error + sc := security.JWTScheme{ + Name: "jwt", + Scopes: []string{}, + RequiredScopes: []string{}, + } + ctx, err = authJWTFn(ctx, p.Token, &sc) + if err != nil { + return nil, err + } + return s.Secure(ctx, p) + } +} diff --git a/go/goa_example/gen/service1/service.go b/go/goa_example/gen/service1/service.go new file mode 100644 index 0000000..0cc7d35 --- /dev/null +++ b/go/goa_example/gen/service1/service.go @@ -0,0 +1,80 @@ +// Code generated by goa v3.6.0, DO NOT EDIT. +// +// Service1 service +// +// Command: +// $ goa gen goa_example/design + +package service1 + +import ( + "context" + + "goa.design/goa/v3/security" +) + +// The secured service exposes endpoints that require valid authorization +// credentials. +type Service interface { + // Signin implements signin. + Signin(context.Context, *SigninPayload) (res *Creds, err error) + // 这是一个需要JWT认证的接口 + Secure(context.Context, *SecurePayload) (res string, err error) +} + +// Auther defines the authorization functions to be implemented by the service. +type Auther interface { + // BasicAuth implements the authorization logic for the Basic security scheme. + BasicAuth(ctx context.Context, user, pass string, schema *security.BasicScheme) (context.Context, error) + // JWTAuth implements the authorization logic for the JWT security scheme. + JWTAuth(ctx context.Context, token string, schema *security.JWTScheme) (context.Context, error) +} + +// ServiceName is the name of the service as defined in the design. This is the +// same value that is set in the endpoint request contexts under the ServiceKey +// key. +const ServiceName = "Service1" + +// MethodNames lists the service method names as defined in the design. These +// are the same values that are set in the endpoint request contexts under the +// MethodKey key. +var MethodNames = [2]string{"signin", "secure"} + +// Creds is the result type of the Service1 service signin method. +type Creds struct { + // JWT token + JWT string + // API Key + APIKey string + // OAuth2 token + OauthToken string +} + +// SecurePayload is the payload type of the Service1 service secure method. +type SecurePayload struct { + // Whether to force auth failure even with a valid JWT + Fail *bool + // JWT used for authentication + Token string +} + +// Credentials used to authenticate to retrieve JWT token +type SigninPayload struct { + // Username used to perform signin + Username string + // Password used to perform signin + Password string +} + +// Credentials are invalid +type Unauthorized string + +// Error returns an error description. +func (e Unauthorized) Error() string { + return "Credentials are invalid" +} + +// ErrorName returns "unauthorized". +func (e Unauthorized) ErrorName() string { + return "unauthorized" +} diff --git a/go/goa_example/go.mod b/go/goa_example/go.mod new file mode 100644 index 0000000..a002f6c --- /dev/null +++ b/go/goa_example/go.mod @@ -0,0 +1,26 @@ +module goa_example + +go 1.17 + +require goa.design/goa/v3 v3.6.0 + +require ( + github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect + github.com/kr/text v0.2.0 // indirect + github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/sergi/go-diff v1.2.0 // indirect + github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect + github.com/stretchr/testify v1.7.0 // indirect + github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea // indirect + golang.org/x/mod v0.5.1 // indirect + golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect + golang.org/x/tools v0.1.9 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect +) diff --git a/go/goa_example/go.sum b/go/goa_example/go.sum new file mode 100644 index 0000000..4977444 --- /dev/null +++ b/go/goa_example/go.sum @@ -0,0 +1,206 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 h1:MGKhKyiYrvMDZsmLR/+RGffQSXwEkXgfLSA08qDn9AI= +github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598/go.mod h1:0FpDmbrt36utu8jEmeU05dPC9AB5tsLYVVi+ZHfyuwI= +github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/getkin/kin-openapi v0.90.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4 h1:OL2d27ueTKnlQJoqLW2fc9pWYulFnJYLWzomGV7HqZo= +github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d h1:Zj+PHjnhRYWBK6RqCDBcAhLXoi3TzC27Zad/Vn+gnVQ= +github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d/go.mod h1:WZy8Q5coAB1zhY9AOBJP0O6J4BuDfbupUDavKY+I3+s= +github.com/manveru/gobdd v0.0.0-20131210092515-f1a17fdd710b h1:3E44bLeN8uKYdfQqVQycPnaVviZdBLbizFhU49mtbe4= +github.com/manveru/gobdd v0.0.0-20131210092515-f1a17fdd710b/go.mod h1:Bj8LjjP0ReT1eKt5QlKjwgi5AFm5mI6O1A2G4ChI0Ag= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea h1:CyhwejzVGvZ3Q2PSbQ4NRRYn+ZWv5eS1vlaEusT+bAI= +github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea/go.mod h1:eNr558nEUjP8acGw8FFjTeWvSgU1stO7FAO6eknhHe4= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +goa.design/goa/v3 v3.6.0 h1:sjOlBL3b4zC1sCdFuv26leFTJGbk48nLRhhTr1suyFA= +goa.design/goa/v3 v3.6.0/go.mod h1:Dmdfd7lWtKpCzpf5HWjvx63ds/lltkbOu4vJSGePq7k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go/goa_example/service1.go b/go/goa_example/service1.go new file mode 100644 index 0000000..292204e --- /dev/null +++ b/go/goa_example/service1.go @@ -0,0 +1,74 @@ +package exampleservice + +import ( + "context" + "fmt" + service1 "goa_example/gen/service1" + "log" + + "goa.design/goa/v3/security" +) + +// Service1 service example implementation. +// The example methods log the requests and return zero values. +type service1srvc struct { + logger *log.Logger +} + +// NewService1 returns the Service1 service implementation. +func NewService1(logger *log.Logger) service1.Service { + return &service1srvc{logger} +} + +// BasicAuth implements the authorization logic for service "Service1" for the +// "basic" security scheme. +func (s *service1srvc) BasicAuth(ctx context.Context, user, pass string, scheme *security.BasicScheme) (context.Context, error) { + // + // TBD: add authorization logic. + // + // In case of authorization failure this function should return + // one of the generated error structs, e.g.: + // + // return ctx, myservice.MakeUnauthorizedError("invalid token") + // + // Alternatively this function may return an instance of + // goa.ServiceError with a Name field value that matches one of + // the design error names, e.g: + // + // return ctx, goa.PermanentError("unauthorized", "invalid token") + // + return ctx, fmt.Errorf("not implemented") +} + +// JWTAuth implements the authorization logic for service "Service1" for the +// "jwt" security scheme. +func (s *service1srvc) JWTAuth(ctx context.Context, token string, scheme *security.JWTScheme) (context.Context, error) { + // + // TBD: add authorization logic. + // + // In case of authorization failure this function should return + // one of the generated error structs, e.g.: + // + // return ctx, myservice.MakeUnauthorizedError("invalid token") + // + // Alternatively this function may return an instance of + // goa.ServiceError with a Name field value that matches one of + // the design error names, e.g: + // + // return ctx, goa.PermanentError("unauthorized", "invalid token") + // + return ctx, fmt.Errorf("not implemented") +} + +// Signin implements signin. +func (s *service1srvc) Signin(ctx context.Context, p *service1.SigninPayload) (res *service1.Creds, err error) { + res = &service1.Creds{} + s.logger.Print("service1.signin") + return +} + +// 这是一个需要JWT认证的接口 +func (s *service1srvc) Secure(ctx context.Context, p *service1.SecurePayload) (res string, err error) { + s.logger.Print("service1.secure") + return +}