swaggo / swag

Automatically generate RESTful API documentation with Swagger 2.0 for Go.
MIT License
10.77k stars 1.2k forks source link

Have Swag generate Swagger definitions nested types #679

Open jancona opened 4 years ago

jancona commented 4 years ago

Is your feature request related to a problem? Please describe. Currently if I define a model struct using nested types like this:

type MyString string

type MyStruct struct {
    Map1 map[string]string
    Map2 map[string]MyString
}

type MyPayload struct {
    Name      string      `json:"name"`
    Map1      map[string]string
    Map2      map[string]MyString
    Struct1 MyStruct
}

When i use it in my service, it generates Swagger like this:

"model.MyPayload": {
            "type": "object",
            "properties": {
                "map1": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "map2": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/model.MyString"
                    }
                },
                "name": {
                    "type": "string"
                },
                "struct1": {
                    "type": "MyStruct"
                }
            }
        },

It doesn't generate definitions for model.MyString or model.MyStruct.

Describe the solution you'd like I'd like Swag to generate definitions for all types referred to by types in my model.

Describe alternatives you've considered

  1. I've looked at swaggertype, but it doesn't support non-primitive types.
  2. If I refer to model.MyString and model.MyStruct in dummy @param declarations, the proper model definitions are generated.

Additional context It looks like calling operation.registerSchemaType on all the types referred to by my model types would fix the issue. But I couldn't figure out where to make those calls.

sdghchj commented 4 years ago

I've refactored a new branch 'refactored', try it please.

jancona commented 4 years ago

Thanks for taking a look! I tried the refactored branch. I still have to add dummy @param or @failure declarations in order to generate definitions for the nested types. I'll review the code again to see if I can figure out how to implement this.

sdghchj commented 4 years ago

My output is

"definitions": {
        "model.MyPayload": {
            "type": "object",
            "properties": {
                "map1": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "map2": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "name": {
                    "type": "string"
                },
                "struct1": {
                    "$ref": "#/definitions/model.MyStruct"
                }
            }
        },
        "model.MyStruct": {
            "type": "object",
            "properties": {
                "map1": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "map2": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                }
            }
        }
    }
jancona commented 4 years ago

That's what I'm looking for. but when I run it, I get:

   "definitions": {
        "model.MyPayload": {
            "type": "object",
            "properties": {
                "map1": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "name": {
                    "type": "string"
                }
            }
        }
    }

I have checked out the refactored branch, and built by running go build in swag/cmd/swag. Is that correct?

jim@jim-mbp:~/jimprojects/swag/cmd/swag$ git status
On branch refactored
Your branch is up to date with 'origin/refactored'.

nothing to commit, working tree clean
jim@jim-mbp:~/jimprojects/swag/cmd/swag$ go build
jim@jim-mbp:~/jimprojects/swag/cmd/swag$ ls -l
total 27208
-rw-r--r--  1 jim  staff      2813 Apr 17 09:47 main.go
-rwxr-xr-x  1 jim  staff  13922572 Apr 19 11:53 swag
jim@jim-mbp:~/jimprojects/swag/cmd/swag$
jancona commented 4 years ago

This is what I have in my server.go file:

// Dummy is a dummy endpoint
// @summary dummy
// @router /dummy [get]
// @success 200 {object} model.MyPayload
func (app App) Dummy(w http.ResponseWriter, req *http.Request) {}
sdghchj commented 4 years ago

I have checked out the refactored branch, and built by running go build in swag/cmd/swag. Is that correct?

Steps are correct. The last step: swag init

Any errror logs ?

jancona commented 4 years ago

Here's the output:

$ /Users/jim/jimprojects/swag/cmd/swag/swag init --generalInfo server.go
2020/04/19 12:08:18 Generate swagger docs....
2020/04/19 12:08:18 Generate general API Info, search dir:./
2020/04/19 12:08:19 Generating model.MyPayload
2020/04/19 12:08:19 create docs.go at docs/docs.go
2020/04/19 12:08:19 create swagger.json at docs/swagger.json
2020/04/19 12:08:19 create swagger.yaml at docs/swagger.yaml

I can add debug Printf statements if you'll tell me where to put them.

jancona commented 4 years ago

If I change my @success line to:

// @success 200 {object} model.MyPayload{struct1=model.MyStruct{map2=map[string]model.MyString}}

I get this output:

    "definitions": {
        "model.MyPayload": {
            "type": "object",
            "properties": {
                "map1": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "map2": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/model.MyString"
                    }
                },
                "name": {
                    "type": "string"
                },
                "struct1": {
                    "$ref": "#/definitions/model.MyStruct"
                }
            }
        },
        "model.MyString": {
            "type": "string"
        },
        "model.MyStruct": {
            "type": "object",
            "properties": {
                "map1": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "map2": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/model.MyString"
                    }
                }
            }
        }
    }
jancona commented 4 years ago

I'm running it from within my project directory. I renamed my program to main.go and ran go install to put my built version of swag in the PATH. The output is the same:

jim@jim-mbp:~/jimprojects/ourroots/server$ swag init
2020/04/19 21:23:20 Generate swagger docs....
2020/04/19 21:23:20 Generate general API Info, search dir:./
2020/04/19 21:23:22 Generating model.MyPayload
2020/04/19 21:23:22 create docs.go at docs/docs.go
2020/04/19 21:23:22 create swagger.json at docs/swagger.json
2020/04/19 21:23:22 create swagger.yaml at docs/swagger.yaml
sdghchj commented 4 years ago

I use go 1.13.5, works well. What your go version?

jancona commented 4 years ago

I'm using 1.14. Are you sure all your changes are pushed to the refactored branch?

sdghchj commented 4 years ago

I'm using 1.14. Are you sure all your changes are pushed to the refactored branch?

sure. I pulled from github just right now and still worked well on CentOS.

jancona commented 4 years ago

I installed go 1.13.5 and got the same results.

sdghchj commented 4 years ago

I installed go 1.13.5 and got the same results.

Seems unbelievable. Try debuging it.

jancona commented 4 years ago

Can you point me to the places in the code where I should be looking? Where does it expand the additional types?

sdghchj commented 4 years ago

Can you point me to the places in the code where I should be looking? Where does it expand the additional types?

parser.go#L824

jancona commented 4 years ago

Okay, I figured it out. I was running swag from within the directory containing my server program, which is a subdirectory of the project directory. So parser.getAllGoFileInfo didn't find the definitions in another package. When I run it from the project directory or with the proper parameters everything works! Thanks for your help!

Should I leave this open until you merge your refactored branch?

sdghchj commented 4 years ago

Should I leave this open until you merge your refactored branch?

I'll add log prompt for missing type definition in refactored branch

sdghchj commented 4 years ago

prompt still need to be optimized in master branch

bendiknesbo commented 4 years ago

Is there any progress on this? Any ETA on when it will be merged and released? :)