goadesign / plugins Goto Github PK
View Code? Open in Web Editor NEWA collection of plugins for Goa.
Home Page: https://goa.design
License: MIT License
A collection of plugins for Goa.
Home Page: https://goa.design
License: MIT License
Hi, I am trying to migrate from goa.design v1 to v2 version.
I am stacked with RemoteAddr. I do need to with client IP address in my HTTP service. Any workaround how do this properly with v2? Thank you.
BTW, @raphael @nitinmohan87 do you have any public slack channel to discuss such questions?
If the output directory is customized, the content to gen/docs.json
keeps getting appended every time the code is generated.
I see we have this code here that attempts to delete the gen/docs.json
file before generating it again but it only works if the output directory is not customized (the default is the current directory).
package brokenDesign
import (
. "goa.design/goa/http/design"
_ "goa.design/plugins/security"
. "goa.design/plugins/security/dsl"
)
var BasicAuth = BasicAuthSecurity("account_auth")
var _ = API("broken", func() {
Title("Broken API Service")
Server("http://localhost:8080")
})
var _ = Service("secured", func() {
Method("no_payload", func() {
Security(BasicAuth)
Result(String)
HTTP(func() {
POST("/no-payload")
Response(StatusOK)
Response(StatusUnauthorized)
})
})
})
The above DSL will cause a panic due to not having a Security defined but no Payload. Expected behavior would be an error describing the missing Payload.
The goa codegen
consistently uses snake_case of the service.Data.VarName
in package paths (both in file system and imports), e.g.: https://github.com/goadesign/goa/blob/v3.5.4/http/codegen/client.go#L32 and https://github.com/goadesign/goa/blob/v3.5.4/http/codegen/server.go#L34
The goakit
plugin, on the other hand, uses snake_cased expr.HTTPServiceExpr.Name()
in generated file system paths, but service.Data.Name
verbatim when importing, e.g.:
plugins/goakit/encode_decode_files.go
Line 28 in 8db24fb
plugins/goakit/encode_decode_files.go
Line 39 in 8db24fb
This breaks the imports in the generated kitserver
/kitclient
packages when service names are camelCased (or even simply Capitalized).
package design
import (
. "goa.design/goa/v3/dsl"
_ "goa.design/plugins/v3/goakit"
)
var _ = Service("SimpleService", func() {
Method("SimpleMethod", func() {
HTTP(func() {
GET("/")
})
})
})
$ goa gen foo/design && \
goa example foo/design
foo/gen/http/simple_service/kitclient
should import foo/gen/http/simple_service/client
foo/gen/http/simple_service/kitserver
should import foo/gen/http/simple_service/server
cmd/simple_service/http.go
should import foo/gen/http/simple_service/kitserver
kitclient
imports foo/gen/http/SimpleService/client
// ... snip ...
package client
import (
"context"
"foo/gen/http/SimpleService/client"
"net/http"
// ... snip ...
)
// ... snip ...
kitserver
imports foo/gen/http/SimpleService/server
// ... snip ...
package server
import (
"context"
"foo/gen/http/SimpleService/server"
"net/http"
// ... snip ...
)
// ... snip ...
cmd/simple_service/http.go
imports foo/gen/http/SimpleService/kitserver
package main
import (
"context"
"fmt"
simpleservicekitsvr "foo/gen/http/SimpleService/kitserver"
simpleservicesvr "foo/gen/http/simple_service/server"
simpleservice "foo/gen/simple_service"
// ... snip ...
)
// ... snip ...
codegen.SnakeCase
d service.Data.VarName
in all the relevant spots.diff --git a/goakit/encode_decode_files.go b/goakit/encode_decode_files.go
index e5e6d2e..a629631 100644
--- a/goakit/encode_decode_files.go
+++ b/goakit/encode_decode_files.go
@@ -25,8 +25,9 @@ func EncodeDecodeFiles(genpkg string, root *expr.RootExpr) []*codegen.File {
// serverEncodeDecode returns the file defining the go-kit HTTP server encoding
// and decoding logic.
func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
- path := filepath.Join(codegen.Gendir, "http", codegen.SnakeCase(svc.Name()), "kitserver", "encode_decode.go")
data := httpcodegen.HTTPServices.Get(svc.Name())
+ svcName := codegen.SnakeCase(data.Service.VarName)
+ path := filepath.Join(codegen.Gendir, "http", svcName, "kitserver", "encode_decode.go")
title := fmt.Sprintf("%s go-kit HTTP server encoders and decoders", svc.Name())
sections := []*codegen.SectionTemplate{
codegen.Header(title, "server", []*codegen.ImportSpec{
@@ -36,7 +37,7 @@ func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
{Path: "github.com/go-kit/kit/transport/http", Name: "kithttp"},
{Path: "goa.design/goa/v3", Name: "goa"},
{Path: "goa.design/goa/v3/http", Name: "goahttp"},
- {Path: genpkg + "/http/" + data.Service.Name + "/server"},
+ {Path: genpkg + "/http/" + svcName + "/server"},
}),
}
@@ -70,9 +71,10 @@ func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
// clientEncodeDecode returns the file defining the go-kit HTTP client encoding
// and decoding logic.
func clientEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
- path := filepath.Join(codegen.Gendir, "http", codegen.SnakeCase(svc.Name()), "kitclient", "encode_decode.go")
- title := fmt.Sprintf("%s go-kit HTTP client encoders and decoders", svc.Name())
data := httpcodegen.HTTPServices.Get(svc.Name())
+ svcName := codegen.SnakeCase(data.Service.VarName)
+ path := filepath.Join(codegen.Gendir, "http", svcName, "kitclient", "encode_decode.go")
+ title := fmt.Sprintf("%s go-kit HTTP client encoders and decoders", svc.Name())
sections := []*codegen.SectionTemplate{
codegen.Header(title, "client", []*codegen.ImportSpec{
{Path: "context"},
@@ -81,7 +83,7 @@ func clientEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
{Path: "github.com/go-kit/kit/transport/http", Name: "kithttp"},
{Path: "goa.design/goa/v3", Name: "goa"},
{Path: "goa.design/goa/v3/http", Name: "goahttp"},
- {Path: genpkg + "/http/" + data.Service.Name + "/client"},
+ {Path: genpkg + "/http/" + svcName + "/client"},
}),
}
diff --git a/goakit/generate.go b/goakit/generate.go
index 8406c51..319e1b5 100644
--- a/goakit/generate.go
+++ b/goakit/generate.go
@@ -106,10 +106,10 @@ func gokitifyExampleServer(genpkg string, file *codegen.File) {
data := s.Data.(map[string]interface{})
svcs := data["Services"].([]*httpcodegen.ServiceData)
for _, svc := range svcs {
- pkgName := httpcodegen.HTTPServices.Get(svc.Service.Name).Service.PkgName
+ svcData := httpcodegen.HTTPServices.Get(svc.Service.Name).Service
codegen.AddImport(file.SectionTemplates[0], &codegen.ImportSpec{
- Path: path.Join(genpkg, "http", svc.Service.Name, "kitserver"),
- Name: pkgName + "kitsvr",
+ Path: path.Join(genpkg, "http", codegen.SnakeCase(svcData.VarName), "kitserver"),
+ Name: svcData.PkgName + "kitsvr",
})
}
s.Source = gokitServerInitT
Testing for it, though, seems somewhat finicky, because this behavior was never covered by tests before (obviously, that's why we have it) and there is currently no clean API path for inspecting the generated imports.
This behavior originates in #6, but I couldn't find anything in there that would explain why should it be done this way.
thing | version |
---|---|
go | go1.17.6 |
goa | v3.5.4 |
plugins | v3.5.4 |
platform | linux/amd64 |
If you have multiple services with the same origin only the last origin will be handled:
var MultiServiceSameOriginDSL = func() {
Service("FirstService", func() {
cors.Origin("SimpleOrigin")
Method("SimpleOriginMethod", func() {
HTTP(func() {
GET("/")
})
})
})
Service("SecondService", func() {
cors.Origin("SimpleOrigin")
Method("SimpleOriginMethod", func() {
HTTP(func() {
GET("/")
})
})
})
}
Here the Access-Control
headers will only be added to the SecondService
.
I think this because the Cors
rules are stored under ServiceOrigins:
Line 22 in 262a1d6
using the origin only. This will overwrite when you use same value. Maybe prefix with the service name or something?
If a method accepts both one-off and streaming payloads, the docs plugin only represents the one-off payload.
Example:
Method("myMethod", func() {
Payload(func() {
...
})
StreamingPayload(func() {
...
})
In docs.json only Payload will be represented.
add second service to included example
var _ = API("calc", func() {
Title("CORS Example Calc API")
cors.Origin("http://127.0.0.1", func() {
cors.Headers("X-Shared-Secret")
cors.Methods("GET", "POST")
cors.Expose("X-Time")
cors.MaxAge(600)
cors.Credentials()
})
})
var _ = Service("calc", func() {
cors.Origin("/.*localhost.*/", func() {
cors.Methods("GET", "POST")
cors.Expose("X-Time", "X-Api-Version")
cors.MaxAge(100)
})
Method("add", func() {
Payload(func() {
Attribute("a", Int, func() {
Description("Left operand")
Example(1)
})
Attribute("b", Int, func() {
Description("Right operand")
Example(2)
})
Required("a", "b")
})
Result(Int, func() {
Description("Result of addition")
Example(3)
})
HTTP(func() {
GET("/add/{a}/{b}")
Response(StatusOK)
})
})
})
var _ = Service("swagger", func() {
cors.Origin("/.*localhost.*/", func() {
cors.Methods("GET")
})
HTTP(func() {
Path("/swagger")
})
Files("/swagger.json", "gen/http/openapi.json", func() {
Description("JSON document containing the API swagger definition")
})
})
regenerate and build examples results in build error
[I] ➜ make build-examples
# goa.design/plugins/v3/cors/examples/calc/cmd/calc
cmd/calc/http.go:63:18: not enough arguments in call to "goa.design/plugins/v3/cors/examples/calc/gen/http/swagger/server".Mount
have ("goa.design/goa/v3/http".Muxer)
want ("goa.design/goa/v3/http".Muxer, *"goa.design/plugins/v3/cors/examples/calc/gen/http/swagger/server".Server)
make: *** [build-examples] Error 2
second service endpoints are missing from call to Mount
According to CVE-2020-26160
jwt-go allows attackers to bypass intended access restrictions in situations with []string{} for m["aud"] (which is allowed by the specification). Because the type assertion fails, "" is the value of aud. This is a security problem if the JWT token is presented to a service that lacks its own audience check. There is no patch available and users of jwt-go are advised to migrate to golang-jwt at version 3.2.1
This repository uses github.com/go-kit/[email protected] which still references github.com/dgrijalva/jwt-go. The latest version v0.12.0 has fixed the dependency.
Can you provide template to write a custom security plugin?
I have authentication service. So I need to take cookie and connect to that service to find the user and also need to keep that user in context. Then only i can access the user inside app logic.
# account/gen/http/user/server
account/gen/http/user/server/server.go:93:77: not enough arguments in call to NewUserUploadPicDecoder
have (UserUploadPicDecoderFunc)
want ("github.com/obo/am/vendor/goa.design/goa/http".Muxer, UserUploadPicDecoderFunc)
I'm building an HTTP REST service with goa and the CORS plugin.
My question:
Is it possible to set the CORS origin at runtime? I don't want to bake the origin into the generated server.
I can't find a solution for this problem, have I overseen something?
Possible solution:
The origin could be, for example, set by an environment variable?
cors.Origin("$CORS_ORIGIN", func() {
// ...
})
And the generated code could then be something like this:
// ...
if cors.MatchOrigin(origin, os.Getenv("CORS_ORIGIN")) {
/// ...
Just an idea though, other ways to set it dynamically would be fine too.
If there is a way to achieve something like this currently, please tell me.
Thanks! :)
Line 169 in 6127466
If a method has no DSL Security Attribute example Security(....) then it fails on build of generated project with "undefined: NewMethodName"
Changing the above line to this
{{ .FieldName }}: {{ .VarName }}{{ if not .Requirements}}Endpoint{{ end }}{{ if .Requirements }}({{ .NonSecureVarName }}{{ end }}(s){{ if .Requirements }}){{ end }},```
It seems to fix the issue, compiles and method is seems to execute correctly. However there is probably easier way to fix this.
steps to repo:
# goa v2
go get -u goa.design/goa
cd /Users/apple/workspace/go/src/goa.design/goa/cmd/goa && go install
goa version
goa version v2.0.0-wip
# now try gokit plugin.
go get -u goa.design/plugins/goakit
package goa.design/plugins/goakit: unrecognized import path "goa.design/plugins/goakit" (parsing goa.design/plugins/goakit: XML syntax error on line 48: expected element name after <)
When using the security plugin there are generated secure request decoders e.g. SecureDecodeFooBarRequest
. However, they don’t work with go-kit endpoints because the return value is func(*http.Request) (interface{}, error)
and not go-kit’s DecodeRequestFunc
which is func(context.Context, *http.Request) (request interface{}, err error)
.
My current workaround is to wrap the secure request decoders:
var dec = goahttp.RequestDecoder
func genericDecodeRequestFunc(muxRouter goahttp.Muxer, secureDecodeRequestFunc func(goahttp.Muxer, func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error)) kithttp.DecodeRequestFunc {
return func(ctx context.Context, r *http.Request) (interface{}, error) {
return secureDecodeRequestFunc(muxRouter, dec)(r)
}
}
CORS does not work for GOA generated grpc servers.
I'm trying to use the goa generated server as a backend for the grpc-web framework. Since the grpc-web framework issues calls from the browser I'm running into problem that I need CORS on the grpc server. Since the CORS plugin adds the handler to the http server I was expecting that this is also done for the grpc server. Any change this features get's implemented?
If you include two service definitions in one file (same API) the generated code adds the same security functions to the created NewSecureEndpoints()
functions in [service]/main.go
for each service. Currently, it uses the security definition from the last defined service in the design file. For example if you define a full service design first that requires security and then a health service without security, the endpoint functions are generated without security endpoints. When code generation makes any modifications to the ...Endpoints()
functions (like making them secure), it does it for every service. This needs to be modified to only change these functions for individual services at a time.
This can be reproduced by using the sample code in goadesign/examples
where the custom div_by_zero
error should give 400 Bad Request
.
However when using the goakit
plugin by simply adding the following line in the design.go
file
import _ "goa.design/plugins/v3/goakit"
and do goa gen ...
then goa example ...
; We do get the correct error message but instead of 400 Bad Request
we get 500 Internal Server Error
:
$ curl -i localhost:8080/div/1.2/0
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Sun, 18 Aug 2019 09:35:06 GMT
Content-Length: 25
right operand cannot be 0
I’m getting an error when using the goakit plugin with the security plugin. The goakit plugin makes the generated code use go-kit’s endpoint.Endpoint
instead of goa’s goa.endpoint
, but endpoint.Endpoint
is not compatible with the goa.Endpoint
.
I was able to workaround this issue by importing goa.design/plugins/security
package before goa.design/plugins/goakit
.
package design
import "goa.design/goa/http/design"
import "goa.design/plugins/security/dsl"
import _ "goa.design/plugins/security" // Needs to be imported before goakit
import _ "goa.design/plugins/goakit"
To reproduce the issue, in your design import the goakit plugin before the security plugin and secure a method.
After the addition of OpenAPI YAML generation, the Required security scopes:
addition to the description is doubled up in both the YAML and JSON output:
description: |-
Index returns the list of thingies in a thing.
Required security scopes:
* `thing:read`
Required security scopes:
* `thing:read`
"description":"Index returns the list of thingies in a thing.\n\nRequired security scopes:\n * `thing:read`\n\nRequired security scopes:\n * `thing:read`"
https://github.com/goadesign/plugins/blob/master/security/examples/calc/README.md
The example in the readme has the following snippet:
// BasicAuth defines a security scheme that uses basic authentication.
var BasicAuth = BasicAuth("basic", func() {
Description("Secures the login endpoint.")
})
I think BasicAuth
should be BasicAuthSecurity
.
I'm consistently getting the following response ("missing required payload") when I try to send a JWT via the Authorization header:
{
"token": "blahblahblah",
"detail": "missing required payload",
"temporary": false,
"timeout": false
}
The workaround is to include dsl.Header("token:Authorization")
in the design for the method:
package design
import "goa.design/goa/http/design"
import "goa.design/plugins/security/dsl"
import _ "goa.design/plugins/security"
...
var _ = dsl.Service("foobar", func() {
...
dsl.Method("secure", func() {
dsl.Description("This action is secured with the jwt scheme")
dsl.Security(JWTAuth, func() {
dsl.Scope("api:read")
})
dsl.Payload(func() {
dsl.Token("token", design.String, func() {
dsl.Description("JWT used for authentication")
})
})
dsl.Result(design.String, func() {
dsl.Example("JWT secured data")
})
dsl.HTTP(func() {
dsl.GET("/secure")
dsl.Header("token:Authorization")
dsl.Response(design.StatusOK)
})
})
...
s.logger has type *log.Logger, which is a wrapper for *zap.SugaredLogger. Since the rest of the system is also using the same wrapper, everything is fine... until:
logger := s.logger.With(
"req", ctx.Value(middleware.RequestIDKey),
"companyID", p.CompanyID,
"vendorID", p.VendorID,
)
Now logger has type *zap.SugaredLogger and can't be passed to functions that expect *log.Logger. It seems like it should be possible to cast it, but that gives me a type conversion error.
I'm pretty sure I'm missing something, but since the zaplogger plugin offers context logging it seems like this should work, and it might be useful to document the use of context logging in the calc example.
I'm using go 1.17.5, goa 3.5.3, and goa plugins v3.5.3. Thanks in advance!
I'm using goa grpc_go_1_26 branch and goakit plugin from v3.2.6.
When I try to build generated examples, I get an error:
> go build -o ./bin/example.exe .\cmd\example\
cmd\example\grpc.go:30:33: cannot use logger (type "github.com/go-kit/kit/log".Logger) as type *"log".Logger in argument to "goa.design/goa/v3/middleware".NewLogger
Cause of this error is that goakit generator in gokitifyExampleServer()
don't replace middleware.NewLogger(logger)
to logger
. As it is done for example in zaplogger's updateExampleFile()
.
My API design definitions:
package design
import (
. "goa.design/goa/v3/dsl"
_ "goa.design/plugins/v3/goakit"
)
var (
_ = API("example", func() {
Title("example")
Version("1.0")
Description("example api description")
Server("example", func() {
Description("example server description")
Services("svc")
Host("development", func() {
Description("Development host")
URI("grpc://localhost:50051")
})
})
})
_ = Service("svc", func() {
Description("svc desc")
Method("mtd", func() {
Payload(MtdReq)
Result(MtdResp)
Error("NotFound")
Error("BadRequest")
GRPC(func() {
Response("NotFound", CodeNotFound)
Response("BadRequest", CodeInvalidArgument)
})
})
})
MtdReq = Type("MtdRequest", func() {
Description("MtdRequest desc")
Attribute("att", ArrayOf(String), "att desc", func() {
Example([]string{
"R",
"T",
})
Meta("rpc:tag", "1")
})
})
MtdResp = Type("MtdResponse", func() {
Description("MtdResponse desc")
Attribute("att", MapOf(String, Boolean), "att desc", func() {
Example(map[string]bool{
"R": true,
"T": true,
})
Meta("rpc:tag", "1")
})
})
)
log plugin is not working.
expect - service.go
// `service.go` generated by goa `example` command.
package service
import (
"{module}/gen/log"
)
now - service.go
// `service.go` generated by goa `example` command.
package service
import (
"log"
)
When running the following command on the terminal, I get a bunch of errors. See the command and output below;
Command
go get -u goa.design/goa/... && go get -u goa.design/plugins/goakit/...
Output
package goa.design/goa/v3/codegen: cannot find package "goa.design/goa/v3/codegen" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/codegen (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/codegen (from $GOPATH) package goa.design/goa/v3/eval: cannot find package "goa.design/goa/v3/eval" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/eval (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/eval (from $GOPATH) package goa.design/goa/v3/expr: cannot find package "goa.design/goa/v3/expr" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/expr (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/expr (from $GOPATH) package goa.design/goa/v3/http/codegen: cannot find package "goa.design/goa/v3/http/codegen" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/http/codegen (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/http/codegen (from $GOPATH) package goa.design/goa/v3/http: cannot find package "goa.design/goa/v3/http" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/http (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/http (from $GOPATH) package goa.design/goa/v3/http/middleware: cannot find package "goa.design/goa/v3/http/middleware" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/http/middleware (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/http/middleware (from $GOPATH) package goa.design/goa/v3/middleware: cannot find package "goa.design/goa/v3/middleware" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/middleware (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/middleware (from $GOPATH) package goa.design/goa/v3/pkg: cannot find package "goa.design/goa/v3/pkg" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/pkg (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/pkg (from $GOPATH) package goa.design/goa/v3/dsl: cannot find package "goa.design/goa/v3/dsl" in any of: /usr/local/Cellar/[email protected]/1.10.8/libexec/go/src/goa.design/goa/v3/dsl (from $GOROOT) /Users/uga/go/src/goa.design/goa/v3/dsl (from $GOPATH)
My service was built in and is still running goa V2 but it seems that the plugin is trying to fetch version 3 (V3) of plugins.
Any help would be appreciated. Please keep in mind, I am a beginner in go.
The following is a sample design
package design
import (
. "goa.design/goa/http/design"
_ "goa.design/plugins/security"
. "goa.design/plugins/security/dsl"
)
var _ = API("dummy", func() {
Title(`Dummy API`)
})
var SomeRequest = Type("ShowItem", func() {
Attribute("id", UInt, "id of something.", func() {
Example(20)
})
Attribute("nested_map", MapOf(String, ArrayOf(MapOf(String, Any))), "The nested map")
Required("id")
})
var _ = Service("dummy", func() {
Description("Foo")
HTTP(func() {
Path("/api/foo")
})
Method("Show", func() {
Description("Show.")
Security(MyJWT, func() {
Scope("show")
})
Payload(func() {
Token("token", String, "JWT token used to perform authorization", func() {
Default("")
})
Attribute("payload", SomeRequest, "The payload")
Required("payload")
})
HTTP(func() {
GET("/")
Response(StatusOK)
})
})
})
var MyJWT = JWTSecurity("MyJWT")
and when generating the code causes a compilation error. The following is the error:
gen/http/dummy/client/cli.go:38:10: cannot use &dummyShowToken (type *string) as type string in assignment
I have a working API without CORS implementation, I wanted to implement CORS and I exactly followed the process mentioned on the CORS docs. I even matched my code with the example code.
The only change I did on my file was, I added this code on API level
cors.Origin("localhost", func() {
cors.Headers("X-Shared-Secret")
cors.Methods("OPTIONS")
cors.Expose("X-Time")
cors.MaxAge(600)
cors.Credentials()
})
And this on Service level.
cors.Origin("/.*localhost.*/", func() {
cors.Methods("GET", "POST")
cors.Expose("X-Time", "X-Api-Version")
cors.MaxAge(100)
})
The error that I am getting is
cmd\kontext\http.go:100:18: not enough arguments in call to "kontext-goa/gen/http/openapi/server".Mount
have ("goa.design/goa/v3/http".Muxer)
want ("goa.design/goa/v3/http".Muxer, *"kontext-goa/gen/http/openapi/server".Server)
←[31mtask: Failed to run task "run-server": task: Failed to run task "build-server": exit status 2
←[0m
It causes an error after I generate the code for the change that I made to implement CORS. Any help would be appreciated.
I've just started looking at GOA for some API definition creation, and came across the OTEL plugin (we're currently looking at possibly migrating over to OTEL for our projects).
Turns out the otel plugin string matches against {{- range Routes }}
when the template has {{- range .Routes }}
instead. (the .
is missing).
This is actually only the first issue that prevents the plugin from working. The second problem is that the location of the replacement does not have the .Path
variable to use (.Path looks to be under the .Routes information, and would require to be under the range portion of the template, giving you something that looks like this.
s.Source = strings.Replace(
s.Source,
`mux.Handle("{{ .Verb }}", "{{ .Path }}", f)`,
`mux.Handle("{{ .Verb }}", "{{ .Path }}", otelhttp.WithRouteTag("{{ .Path }}", f).ServeHTTP)`,
1,
)
I'm not overly familiar with otel mappings, otherwise I would open a PR myself and offer up a solution, but this is my first foray into goa, plugins, and otel, so I think this is what was expected to happen.
So far I've been enjoying learning about GOA and hope that it can fit our needs. Thanks for creating/supporting it!
This is the correct code:
However, when i run this myself i get errors when two lines are generated as one:
Here is one of the offending functions with bold for the error:
// BuildShowRequest instantiates a HTTP request object with method and path set
// to call the storage show endpoint.
func (c *Client) BuildShowRequest(v interface{}) (*http.Request, error) {
p, ok := v.(*storage.ShowPayload)
if !ok {
return nil, goahttp.ErrInvalidType("storage", "show", "*storage.ShowPayload", v)
}
**var id stringid = p.ID**
u := &url.URL{Scheme: c.scheme, Host: c.host, Path: ShowStoragePath(id)}
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, goahttp.ErrInvalidURL("storage", "show", u.String(), err)
}
return req, nil
}
The error occurs in 6 places as part of the encoder / decoder.
cd /Users/apple/workspace/go/src/github.com/gedw99/gitty/exp/services/gokit/cell/cmd/cellarcli && go run main.go
# github.com/gedw99/gitty/exp/services/gokit/cell/gen/http/sommelier/client
../../gen/http/sommelier/client/encode_decode.go:23:11: undefined: v
../../gen/http/sommelier/client/encode_decode.go:25:82: undefined: v
# github.com/gedw99/gitty/exp/services/gokit/cell/gen/http/storage/client
../../gen/http/storage/client/encode_decode.go:75:9: undefined: stringid
../../gen/http/storage/client/encode_decode.go:135:11: undefined: v
../../gen/http/storage/client/encode_decode.go:137:75: undefined: v
../../gen/http/storage/client/encode_decode.go:207:9: undefined: stringid
make: *** [run] Error 2
make file to repo:
# ref: goa and gokit
# https://github.com/goadesign/goa/tree/v2
DIR=${PWD}
GOA_GO_PATH=goa.design/goa
GOA_FILE_PATH=${GOPATH}/src/${GOA_GO_PATH}
GOAPLUG_GO_PATH=goa.design/plugins
GOAPLUG_FILE_PATH=${GOPATH}/src/${GOAPLUG_GO_PATH}
EX_GO_PATH=goa.design/plugins/goakit/examples/cellar/design
EX_FILE_PATH=${GOPATH}/src/${EX_GO_PATH}
EX_ALIAS_PATH=${DIR}/cell
check:
@echo "## Checking paths"
@echo "DIR \t \t ${DIR}"
@echo
@echo "GOA_GO_PATH: \t ${GOA_GO_PATH}"
@echo "GOA_FILE_PATH: \t ${GOA_FILE_PATH}"
@echo
@echo "GOAPLUG_GO_PATH: \t ${GOAPLUG_GO_PATH}"
@echo "GOAPLUG_FILE_PATH: \t ${GOAPLUG_FILE_PATH}"
@echo
@echo "EX_GO_PATH: \t ${EX_GO_PATH}"
@echo "EX_FILE_PATH: \t ${EX_FILE_PATH}"
@echo
@echo "EX_ALIAS_PATH: \t ${EX_ALIAS_PATH}"
@echo
dep:
# goa v2
go get -u ${GOA_GO_PATH}/...
cd ${GOA_FILE_PATH}/cmd/goa && go install
# check goa tools are there
goa version
# get gokit plugin and examples
go get -u ${GOAPLUG_GO_PATH}/...
dep-clean:
# delete ex code
rm -rf ${GOA_FILE_PATH}
rm -rf ${GOAPLUG_FILE_PATH}
gen:
# Now try the cellar example
# ref: https://github.com/goadesign/plugins/tree/master/goakit/examples/cellar
mkdir ${EX_ALIAS_PATH}
cd ${EX_ALIAS_PATH} && goa gen ${EX_GO_PATH}
cd ${EX_ALIAS_PATH} && goa example ${EX_GO_PATH}
gen-clean:
# delete generated code
rm -rf ${EX_ALIAS_PATH}
open-bash:
# open bash terminal
open -a Terminal.app ${EX_ALIAS_PATH}
open-fs:
# Opens Finder.
open ${EX_ALIAS_PATH}
open-vsc:
# Opens Visual Studio Code
code ${EX_ALIAS_PATH}
open-vs:
# Opens Visual Studio for Mac
open ${EX_ALIAS_PATH}
# Works and runs :)
run:
cd ${EX_ALIAS_PATH}/cmd/cellarcli && go run main.go
build:
cd ${EX_ALIAS_PATH}/cmd/cellarcli && go build
A change after goa 3.09 has introduced a bug into the generated CORS code which prevents servers from compiling or running.
This seems to be the change, in http/service/server/server.go :
-// Code generated by goa v3.0.9, DO NOT EDIT.
+// Code generated by goa v3.1.1, DO NOT EDIT.
- CORS: NewCORSHandler(),
+ CORS: NewCORSHandler(e.CORS, mux, decoder, encoder, errhandler, formatter),
I use a blanket CORS definition inside the API definition.
Attempting to implement the CORS plugin following documentation here https://goa.design/extend/plugins/
this results in a build error
gen/http/account/server/server.go:72:2: f declared and not used
using:
goa version v3.0.2
package design
import (
. "goa.design/goa/v3/dsl"
cors "goa.design/plugins/v3/cors/dsl"
)
var _ = Service("swagger", func() {
Description("The swagger service serves the API swagger definition.")
// Add CORS policy using the CORS DSLs
cors.Origin("/.*localhost.*/", func() {
cors.Headers("X-Shared-Secret")
cors.Methods("GET", "POST")
cors.Expose("X-Time", "X-Api-Version")
cors.MaxAge(100)
cors.Credentials()
})
HTTP(func() {
Path("/swagger")
})
Files("/swagger.json", "gen/http/openapi.json", func() {
Description("JSON document containing the API swagger definition")
})
})
Hi @raphael , Thank you for the nice plugins.
Currently, if we set cors.Origin('*')
, the plugin will set the request's Origin
header (eg example.com
) to Access-Control-Allow-Origin
response header. This is not mistake, but it also need to set Vary: Origin
response header.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Allow-Origin
If the server specifies a single origin (that may dynamically change based on the requesting origin as part of a white-list) rather than the "*" wildcard, then the server should also include Origin in the Vary response header to indicate to clients that server responses will differ based on the value of the Origin request header.
But, CORS plugin doesn't set Vary: Origin
response header, when we set cors.Origin('*')
.
https://github.com/goadesign/plugins/blob/v3/cors/generate.go#L206-L208
Thank you.
design.go
:
package design
import (
. "goa.design/goa/v3/dsl"
cors "goa.design/plugins/v3/cors/dsl"
)
var _ = Service("calc", func() {
Description("The calc service exposes public endpoints that defines CORS policy.")
// Add CORS policy using the CORS DSLs
cors.Origin("*", func() {
cors.Credentials()
})
Method("test", func() {
Result(Int)
HTTP(func() {
GET("/test")
Response(StatusOK)
})
})
})
and then, run application.
$ curl http://localhost:8080/test -H 'Origin: example.com' -i
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: example.com
Content-Type: application/json
Date: Tue, 08 Dec 2020 01:17:45 GMT
Content-Length: 2
0
When we define security DSL In the design and Define Token in the payload and mark token as not required the generated code panics with runtime error: invalid memory address or nil pointer dereference
Ex:
Method("Example", func() {
Security(JWTAuth, func() {
Scope("gaps:write")
})
Payload(func() {
Token("token", String, "JWT token used to perform authorization")
Attribute("Id", UInt, "ID identifies a resource by ID.")
Required("Id")
})
})
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.