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

Support null Package and Data-Types #985

Open
naftulikay opened this issue Aug 25, 2021 · 13 comments
Open

Support null Package and Data-Types #985

naftulikay opened this issue Aug 25, 2021 · 13 comments
Labels

Comments

@naftulikay
Copy link

Describe the bug

swag init fails when compiling models which contain structs from the gopkg.in/guregu/null.v4 package.

To Reproduce

I have a PATCH endpoint where every field is optional, so my struct looks like this:

import "gopkg.in/guregu/null.v4"

type Request struct {
    Email null.String
    IsAdmin null.Bool
}

Having marked up my endpoint like so:

// UserUpdateHandler godoc
// ...
// @Param user body models.Request true "Updated user data."
// ...

When I run swag init, it chokes on items in the gopkg.in/guregu/null.v4 package:

2021/08/25 15:50:45 ParseComment error in file pkg/routes/sadmin/users/root.go :cannot find type definition: null.Bool

Expected behavior

I expected for swag to understand that null.* are simply nullable types.

Screenshots
If applicable, add screenshots to help explain your problem.

Your swag version

1.7.1

Your go version

go version go1.16.6 linux/amd64

Desktop (please complete the following information):

  • OS: elementary OS Loki (Ubuntu 16.04 LTS) amd64

Additional context

If I shouldn't be using the null.* times for optional values in models, what should I be using?

@SmartPhoneJava
Copy link

Try instead of

import "gopkg.in/guregu/null.v4"

type Request struct {
    Email null.String
    IsAdmin null.Bool
}

this one

import null "gopkg.in/guregu/null.v4"

type Request struct {
    Email null.String
    IsAdmin null.Bool
}

@ubogdan
Copy link
Contributor

ubogdan commented Sep 24, 2021

@naftulikay, have you figured it out?

@naftulikay
Copy link
Author

@SmartPhoneJava why would changing the imported package name work? Is there some logic within swaggo that will understand it if I force the package name? The code above does compile.

@ubogdan I haven't tested this yet because I don't see how it would work differently. I'll attempt it at some point. Can you link to code or documentation that covers how this works?

@ubogdan
Copy link
Contributor

ubogdan commented Sep 25, 2021

@naftulikay If the suggested workaround works it means there is an issue in the swag parser related to strings.Split.
Swagger is Open Source. Feel free to look at the source code.

Please test and let us know.

@SmartPhoneJava
Copy link

SmartPhoneJava commented Sep 25, 2021

@naftulikay swaggo has different strategies to parse named and unnamed imports for detecting imported types.

You can see it in https://github.com/swaggo/swag/blob/master/packages.go#L245

I have an assumption that in the case of an unnamed import, swaggo uses the part after the slash as the package name. For gopkg.in/guregu/null.v4 it is null.v4. Accordingly, instead of null.String, swaggo expects null.v4.String, which is incorrect.

Check whether the import naming will work and everything will become clear :)

@naftulikay
Copy link
Author

I tried it out, and no dice:

pkg/routes/login/root.go:

package login

import (
    // ...
   null "gopkg.in/guregu/null.v4"
)

// LoginHandler godoc
// @Summary Login
// @Tags auth
// @Description Log a user in using email and password.
// @Accept json
// @Param login body views.LoginRequest true "Login Credentials"
// @Produce json
// @Success 200 {object} views.Response{data=views.LoginResponse}
// @Failure 400 {object} views.Response
// @Failure 403 {object} views.Response
// @Router /login [post]
func LoginHandler(w http.ResponsWriter, r *http.Request) {
    // ...
    resp := views.LoginRequest {
        // ...
    }

    if err := json.NewEncoder(w).Encode(resp); err != nil {
        // ...
    }
}

pkg/views/root.go:

package views

import (
    // ...
    null "gopkg.in/guregu/null.v4"
)

type Response struct {
	StatusCode uint16        `json:"status_code"`
	Error      null.String   `json:"error"`
	Data       interface{}   `json:"data"`
	Links      ResponseLinks `json:"_links"`
}

type ResponseLinks struct {
	Self string      `json:"_self"`
	Prev null.String `json:"_prev,omitempty"`
	Next null.String `json:"_next,omitempty"`
}

If I add swaggertype:"string" to each of the null.String fields, it does, in fact, work.

@ubogdan @SmartPhoneJava is there anything else I should try?

@ubogdan
Copy link
Contributor

ubogdan commented Oct 3, 2021

@naftulikay Thanks for letting us know about the issue.

A quick dirty workaround is to use "swaggertype" to override the value with a primitive as you described above.

@ubogdan ubogdan added the bug label Oct 3, 2021
@naftulikay
Copy link
Author

@ubogdan Is there a swagger struct field tag that I can use to mark a struct field as optional? I'm using swaggertype:"string" for my null.String values, but is there a way that I can inform the user that this is an optional value and does not need to be included?

@naftulikay
Copy link
Author

@ubogdan ping on this: is there a tag that I can use to let Swagger know the field can be null?

@ubogdan
Copy link
Contributor

ubogdan commented Oct 19, 2021

You can use validate:"required" to signal that field is not optional :).

@naftulikay
Copy link
Author

Is there a validate: "not-required" to signal that a field is indeed optional? Right now with swaggertype:"string" it shows all fields as required when any null.* type should be optional.

@bluebrown
Copy link

Hi, I am getting those structs from https://github.com/volatiletech/sqlboiler, so I cannot really add those tags or the way it imports null. Is there a solution to this?

@Matrix53
Copy link
Contributor

Matrix53 commented Mar 2, 2022

Hello, I also meet a similar problem, and here is my code:

// api comment
// @Param       data  body      api.Problem  true  "comment"
import "mime/multipart"

type Problem struct {
	Input        *multipart.FileHeader `form:"input"`
	Output       *multipart.FileHeader `form:"output"`
}

And when I run swag init, the error occurs:

ParseComment error in file :cannot find type definition: multipart.FileHeader

So the only solution now is to use swaggertype or swaggerignore?

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

No branches or pull requests

5 participants