[BUG][Go] Generated go client cannot upload file
Created by: dhontecillas
Bug Report Checklist
-
Have you provided a full/minimal spec to reproduce the issue? repo with code spec and code to reproduce -
Have you validated the input using an OpenAPI validator (example)? -
Have you tested with the latest master to confirm the issue still exists? -
Have you searched for related issues/PRs? -
What's the actual output vs expected output?
Description
Have an OpenAPI v3 endpoint definition to upload a file, like the one provided in the repo, when you create the client, and try to execute an upload, you get a Invalid body type
error. (You should get a connection error or similar if the client request was sent).
How to reproduce
The Makefile
uses the dockerized version of the openapi-generator-cli
tool, so first:
docker pull openapitools:/openapi-generator-cli
Once you have the image just run:
make buildclient
That will create a pkg/bug
dir with the generated code, then run:
go run .
See the output has an "Invalid body type"
Identifying the issue
Once the code is generated, we can find the error string comes from the file pkg/bug/client.go
, in the function setBody
.
func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) {
if bodyBuf == nil {
bodyBuf = &bytes.Buffer{}
}
if reader, ok := body.(io.Reader); ok {
_, err = bodyBuf.ReadFrom(reader)
} else if b, ok := body.([]byte); ok {
_, err = bodyBuf.Write(b)
} else if s, ok := body.(string); ok {
_, err = bodyBuf.WriteString(s)
} else if s, ok := body.(*string); ok {
_, err = bodyBuf.WriteString(*s)
} else if jsonCheck.MatchString(contentType) {
err = json.NewEncoder(bodyBuf).Encode(body)
} else if xmlCheck.MatchString(contentType) {
err = xml.NewEncoder(bodyBuf).Encode(body)
}
if err != nil {
return nil, err
}
if bodyBuf.Len() == 0 {
err = fmt.Errorf("Invalid body type %s\n", contentType)
return nil, err
}
return bodyBuf, nil
}
The problem is not an invalid body type, but a 0 content length.
And that happens because in pkg/bug/api_default.go
file, the function to set the Body is:
func (r ApiUploadContentRequest) Body(body *os.File) ApiUploadContentRequest {
r.body = &body
return r
}
r.body is not of type *os.File
but **os.File
, see the generated struct
type ApiUploadContentRequest struct {
ctx _context.Context
ApiService *DefaultApiService
body **os.File
}
so, when this part of setBody
function is executed, the **os.File
does not implement the io.Reader
interface, and the body is not read.
if reader, ok := body.(io.Reader); ok {
_, err = bodyBuf.ReadFrom(reader)
} else if b, ok := body.([]byte); ok {
openapi-generator version
latest
OpenAPI declaration file content or url
openapi.yaml in provided public repo
Generation Details
Provided a Makefile
Steps to reproduce
Provided in the description section.
Related issues/PRs
No that I know
Suggest a fix
- Naive one is to add an if case in the client template:
if reader, ok := body.(io.Reader); ok {
_, err = bodyBuf.ReadFrom(reader)
} else if readerPtr, ok := body.(*io.Reader); ok {
_, err = bodyBuf.ReadFrom(*readrPtr)
} else if b, ok := body.([]byte); ok {
- Change the code generation so the body filed in the
struct becomes of type
*os.File
type ApiUploadContentRequest struct {
ctx _context.Context
ApiService *DefaultApiService
body *os.File
}
That might involve something related with the AbstractGoCodegen.java file ?