Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead #3357

Closed
juancanchi1992 opened this issue Sep 11, 2023 · 6 comments · Fixed by #3374

Comments

@juancanchi1992
Copy link

juancanchi1992 commented Sep 11, 2023

'panic: chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead
I have a problem with new version in goa.design v3.13.0:

var _ = Service("swagger", func() {
	Meta("swagger:generate", "false")
	Description("The swagger service serves the API swagger definition.")

	Method("jsonSpecification", func() {
		Result(MapOf(String, Any))
		HTTP(func() {
			GET("swagger/swagger.json")
			Response(StatusOK, func() {
				ContentType(jsonContentType)
			})
		})

	})
	Files("/swagger-ui/{*path}", "./swagger-ui", func() {
		Description("This path contains the Swagger UI files")
	})
})

It occurs when trying to mount the service.

swaggersvr.Mount(mux, swaggerServer)

@veldrane
Copy link

veldrane commented Sep 15, 2023

I have the same problem, tested on version 3.7.2 and it works fine:

$ cat design/swagger.go 
package design

import . "goa.design/goa/v3/dsl"

var _ = Service("swagger", func() {
	Files("/swagger-ui/index.html", "public/swagger/index.html", func() {
		Description("Serve home page.")
		Docs(func() {
			Description("Additional documentation")
			URL("https://goa.design")
		})
	})
	Files("/swagger-ui/{*path}", "public/swagger", func() {
		Description("Serve static content.")
	})
	Meta("swagger:generate", "false")
})

output:

$ ./simpleoidc 
panic: chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead

goroutine 1 [running]:
github.com/go-chi/chi/v5.patNextSegment({0x74212f, 0x5})
	/home/veldrane/go/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/tree.go:754 +0x145
github.com/go-chi/chi/v5.(*node).InsertRoute(0x0?, 0xc0001b7b88?, {0x742123, 0x11}, {0x7c1e60, 0xc0000a66a8})
	/home/veldrane/go/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/tree.go:157 +0xbb
github.com/go-chi/chi/v5.(*Mux).handle(0xc0000aa2a0, 0xc00009b4d0?, {0x742123, 0x11}, {0x7c1e60, 0xc0000a66a8})
	/home/veldrane/go/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/mux.go:410 +0x2c5
github.com/go-chi/chi/v5.(*Mux).Method(0xc0000aedc0?, {0x73dc92, 0x3}, {0x742123, 0x11}, {0x7c1e60, 0xc0000a66a8})
	/home/veldrane/go/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/mux.go:126 +0x96
goa.design/goa/v3/http.(*mux).Handle(0xc0000b8460, {0x73dc92, 0x3}, {0x742123, 0x11}, 0xc0000a6648?)
	/home/veldrane/go/pkg/mod/goa.design/goa/v3@v3.13.0/http/mux.go:93 +0xf6
simpleoidc/gen/http/swagger/server.MountPublicSwagger({0x7f7bde93c0e8, 0xc0000b8460}, {0x7c1e60?, 0xc0000d56c0})
	/home/veldrane/bitbucket/private/simple-oidc-go/src/simpleoidc/gen/http/swagger/server/server.go:99 +0x110
simpleoidc/gen/http/swagger/server.Mount({0x7f7bde93c0e8, 0xc0000b8460}, 0xc0000d5500)
	/home/veldrane/bitbucket/private/simple-oidc-go/src/simpleoidc/gen/http/swagger/server/server.go:81 +0xfd
main.handleHTTPServer({0x7c3a40?, 0xc0000ac230}, 0xc0001be000, 0x0?, 0x748a5a?, 0xc00009c440, 0xc00008e0c0, 0xc0000ac1e0, 0x0)
	/home/veldrane/bitbucket/private/simple-oidc-go/src/simpleoidc/cmd/simpleoidc/http.go:76 +0x48b
main.main()
	/home/veldrane/bitbucket/private/simple-oidc-go/src/simpleoidc/cmd/simpleoidc/main.go:99 +0x812

server.go:99

import (
        "context"
        "net/http"
        swagger "simpleoidc/gen/swagger"
        // path module is missing 
        goahttp "goa.design/goa/v3/http"
)



func MountPublicSwagger(mux goahttp.Muxer, h http.Handler) {
        mux.Handle("GET", "/swagger-ui/", h.ServeHTTP)
        mux.Handle("GET", "/swagger-ui/*path", h.ServeHTTP)
}

All stuff regarding the path module is missing.

@gregwebs
Copy link

gregwebs commented Sep 27, 2023

This happened to me after upgrading goa.

    goa.design/goa/v3 v3.12.3
    goa.design/goa/v3 v3.13.1

There was a change in routers

github.com/dimfeld/httptreemux/v5 v5.5.0 // indirect 
github.com/go-chi/chi/v5 v5.0.10 // indirect 

So the solution is to downgrade.
I don't believe there is any way to fix this for an end user.
This could easily be fixed in server.go, but that's a generated file, so the fix will be overwritten.

Here is the chi example file server. It is expecting the user to perform a prefix strip.

@akm
Copy link

akm commented Sep 27, 2023

This problem is reproduced in examples/files with modifying design/design.go like this:

index aba49c1f..5ebde889 100644
--- a/files/design/design.go
+++ b/files/design/design.go
@@ -5,8 +5,5 @@ import (
 )
 
 var _ = Service("openapi", func() {
-       Files("/openapi.json", "gen/http/openapi.json")
-       Files("/openapi.yaml", "gen/http/openapi.yaml")
-       Files("/openapi3.json", "gen/http/openapi3.json")
-       Files("/openapi3.yaml", "gen/http/openapi3.yaml")
+       Files("/static/{*path}", "gen/http")
 })

After modifying design/design.go, you can see the error with the following steps.

  1. Regenerate gen
  2. Regenerate cmd
  3. Start server
on v3.13.1 (Error on starting server)
$ git log -1 --oneline           
90b30122 (HEAD -> master, origin/master, origin/HEAD) Bump google.golang.org/grpc from 1.58.1 to 1.58.2 (#129)
$ rm -rf gen && goa gen goa.design/examples/files/design && \
  rm -rf cmd && goa example goa.design/examples/files/design && \
  go run ./cmd/openapi -http-port 8080
gen/http/cli/openapi/cli.go
gen/http/openapi.json
gen/http/openapi.yaml
gen/http/openapi/client/client.go
gen/http/openapi/client/encode_decode.go
gen/http/openapi/client/paths.go
gen/http/openapi/client/types.go
gen/http/openapi/server/paths.go
gen/http/openapi/server/server.go
gen/http/openapi/server/types.go
gen/http/openapi3.json
gen/http/openapi3.yaml
gen/openapi/client.go
gen/openapi/endpoints.go
gen/openapi/service.go
cmd/openapi-cli/http.go
cmd/openapi-cli/main.go
cmd/openapi/http.go
cmd/openapi/main.go
panic: chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead

goroutine 1 [running]:
github.com/go-chi/chi/v5.patNextSegment({0x10079ceee, 0x5})
        $HOME.asdf/installs/golang/1.20.7/packages/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/tree.go:754 +0x11c
github.com/go-chi/chi/v5.(*node).InsertRoute(0x140001afba8?, 0x10078abf4?, {0x10079cee6, 0xd}, {0x100897c40, 0x1400011a5a0})
        $HOME.asdf/installs/golang/1.20.7/packages/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/tree.go:157 +0x9c
github.com/go-chi/chi/v5.(*Mux).handle(0x1400011e1e0, 0x1400010f530?, {0x10079cee6, 0xd}, {0x100897c40, 0x1400011a5a0})
        $HOME.asdf/installs/golang/1.20.7/packages/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/mux.go:410 +0x264
github.com/go-chi/chi/v5.(*Mux).Method(0x14000128dc0?, {0x10079a175, 0x3}, {0x10079cee6, 0xd}, {0x100897c40, 0x1400011a5a0})
        $HOME.asdf/installs/golang/1.20.7/packages/pkg/mod/github.com/go-chi/chi/v5@v5.0.10/mux.go:126 +0x88
goa.design/goa/v3/http.(*mux).Handle(0x1400011a558, {0x10079a175, 0x3}, {0x10079cee6, 0xd}, 0x100b94a68?)
        $HOME.asdf/installs/golang/1.20.7/packages/pkg/mod/goa.design/goa/v3@v3.13.1/http/mux.go:102 +0x170
goa.design/examples/files/gen/http/openapi/server.MountGenHTTP({0x127f789f8, 0x1400011a558}, {0x100897c40?, 0x14000123540})
        /path/to/goadesign/examples/files/gen/http/openapi/server/server.go:84 +0x11c
goa.design/examples/files/gen/http/openapi/server.Mount({0x127f789f8, 0x1400011a558}, 0x0?)
        /path/to/goadesign/examples/files/gen/http/openapi/server/server.go:73 +0x58
main.handleHTTPServer({0x1008995b0?, 0x14000126230}, 0x140001be000, 0x14000112440, 0x140001000c0, 0x140001261e0, 0x0)
        /path/to/goadesign/examples/files/cmd/openapi/http.go:64 +0x264
main.main()
        /path/to/goadesign/examples/files/cmd/openapi/main.go:75 +0x690
exit status 2
on v3.12.4 (OK)
$ git log -1 --oneline                                       
10e447c5 (HEAD -> master, tag: v3.12.4) Release v3.12.4
$ rm -rf gen && goa gen goa.design/examples/files/design && \
rm -rf cmd && goa example goa.design/examples/files/design && \
go run ./cmd/openapi -http-port 8080
gen/http/cli/openapi/cli.go
gen/http/openapi.json
gen/http/openapi.yaml
gen/http/openapi/client/client.go
gen/http/openapi/client/encode_decode.go
gen/http/openapi/client/paths.go
gen/http/openapi/client/types.go
gen/http/openapi/server/paths.go
gen/http/openapi/server/server.go
gen/http/openapi/server/types.go
gen/http/openapi3.json
gen/http/openapi3.yaml
gen/openapi/client.go
gen/openapi/endpoints.go
gen/openapi/service.go
cmd/openapi-cli/http.go
cmd/openapi-cli/main.go
cmd/openapi/http.go
cmd/openapi/main.go
[openapiapi] 19:15:48 HTTP "gen/http" mounted on GET /static
[openapiapi] 19:15:48 HTTP server listening on "localhost:8080"
$ curl -i http://localhost:8080/static/openapi.json
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 1686
Content-Type: application/json
Last-Modified: Wed, 27 Sep 2023 10:39:12 GMT
Date: Wed, 27 Sep 2023 10:39:23 GMT

{"swagger":"2.0","info":{"title":"","version":""},"host":"localhost:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/static/{path}":{"get":{"tags":["openapi"],"summary":"Download gen/http","operationId":"openapi#/static/{*path}","parameters":[{"name":"path","in":"path","description":"Relative file path","required":true,"type":"string"}],"responses":{"200":{"description":"File downloaded","schema":{"type":"file"}},"404":{"description":"File not found","schema":{"$ref":"#/definitions/Error"}}},"schemes":["http"]}}},"definitions":{"Error":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Error response result type (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]}}}

I'd like to know how to handle static files by dsl.Files function with wildcard on v3.13.0 or later.

FYI: using dsl.Files with "/static/*"

Modifying design/design.go like this:

package design

import (
	. "goa.design/goa/v3/dsl"
)

var _ = Service("openapi", func() {
	Files("/static/*", "gen/http")
})

the server starts without errors, but it returns 301 for existing file

$ curl -i http://localhost:8080/static/openapi.json
HTTP/1.1 301 Moved Permanently
Location: http/
Date: Wed, 27 Sep 2023 10:29:06 GMT
Content-Length: 0

@gregwebs
Copy link

chi router was introduced in this PR.

I believe this needs to be fixed in the generator by generating different code. For chi it needs to strip a prefix. Some experimentation would be needed to determine how to best generate code in a backwards compatible way. Another possibility is rolling back the upgrade to chi.

Some direction from @raphael on how to approach fixing this would be useful.

If you need to use GOA 3.13.1 and need this feature the only approach I know of is to make an out of band file server that is not generated by the GOA DSL. This should be straightforward, and can be added to your http.go, but it won't show up in the OpenAPI description unless it can be setup to override the route that is being generated by GOA.

@raphael
Copy link
Member

raphael commented Sep 29, 2023

This was indeed a regression introduced with the change to chi. This is fixed by #3374. Thank you for the nice repro!

@akm
Copy link

akm commented Oct 2, 2023

I confirmed that the problem was fixed. Thank you! @raphael

server
$ git diff design 
diff --git a/files/design/design.go b/files/design/design.go
index aba49c1f..5ebde889 100644
--- a/files/design/design.go
+++ b/files/design/design.go
@@ -5,8 +5,5 @@ import (
 )
 
 var _ = Service("openapi", func() {
-       Files("/openapi.json", "gen/http/openapi.json")
-       Files("/openapi.yaml", "gen/http/openapi.yaml")
-       Files("/openapi3.json", "gen/http/openapi3.json")
-       Files("/openapi3.yaml", "gen/http/openapi3.yaml")
+       Files("/static/{*path}", "gen/http")
 })
$ git log -1 --oneline
349b5c24 (HEAD -> master, tag: v3.13.2, origin/master, origin/HEAD) Release v3.13.2
$ go get 
$ rm -rf gen && goa gen goa.design/examples/files/design && \
  rm -rf cmd && goa example goa.design/examples/files/design && \
  go run ./cmd/openapi -http-port 8080
gen/http/cli/openapi/cli.go
gen/http/openapi.json
gen/http/openapi.yaml
gen/http/openapi/client/client.go
gen/http/openapi/client/encode_decode.go
gen/http/openapi/client/paths.go
gen/http/openapi/client/types.go
gen/http/openapi/server/paths.go
gen/http/openapi/server/server.go
gen/http/openapi/server/types.go
gen/http/openapi3.json
gen/http/openapi3.yaml
gen/openapi/client.go
gen/openapi/endpoints.go
gen/openapi/service.go
cmd/openapi-cli/http.go
cmd/openapi-cli/main.go
cmd/openapi/http.go
cmd/openapi/main.go
[openapiapi] 10:34:14 HTTP "gen/http" mounted on GET /static
[openapiapi] 10:34:14 HTTP server listening on "localhost:8080"
[openapiapi] 10:34:28 id=3RRQy03j req=GET /static/openapi.json from=127.0.0.1
[openapiapi] 10:34:28 id=3RRQy03j status=200 bytes=1686 time=3.390417ms
curl
$ curl -i http://localhost:8080/static/openapi.json          
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 1686
Content-Type: application/json
Last-Modified: Mon, 02 Oct 2023 01:34:12 GMT
Date: Mon, 02 Oct 2023 01:34:28 GMT

{"swagger":"2.0","info":{"title":"","version":""},"host":"localhost:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/static/{path}":{"get":{"tags":["openapi"],"summary":"Download gen/http","operationId":"openapi#/static/{*path}","parameters":[{"name":"path","in":"path","description":"Relative file path","required":true,"type":"string"}],"responses":{"200":{"description":"File downloaded","schema":{"type":"file"}},"404":{"description":"File not found","schema":{"$ref":"#/definitions/Error"}}},"schemes":["http"]}}},"definitions":{"Error":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Error response result type (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]}}}%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants