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

text/plain results in an undefined response type with Golang Swagger #10997

Open
pen-gocaspi opened this issue Apr 29, 2021 · 1 comment
Open

Comments

@pen-gocaspi
Copy link

pen-gocaspi commented Apr 29, 2021

Description

Hello, when im generating Golang code for a simple endpoint that returns plain text the generated client runs in an error:
undefined response type . I added the code snippets below.

Swagger-codegen version

2.0

Swagger declaration file content or url
---
swagger: "2.0"
info:
  description: "something"
  version: "v2.6"
  title: "something"
  contact:
    email: "[email protected]"
host: "something.de"
tags:
- name: "administration"
  description: "Meta services"
schemes:
- "https"
- "http"
consumes:
- "application/json"
produces:
- "application/json"
security:
- basicAuth: []
paths:
  /about/version:
    get:
      tags:
      - "administration"
      summary: "current software version"
      description: "Returns the current something version"
      produces:
      - "text/plain"
      parameters: []
      responses:
        "200":
          description: "successful operation"
          schema:
            type: "string"
            example: "1.9.44-04345"
        "400":
          description: "bad request"
          schema:
            $ref: "#/definitions/ErrorMessage"
        "500":
          description: "internal server error"
          schema:
            $ref: "#/definitions/ErrorMessage"
securityDefinitions:
  basicAuth:
    type: "basic"
definitions:
  ErrorMessage:
    type: "object"
    properties:
      errorMessage:
        type: "string"
Command line used for generation

https://editor.swagger.io/

Steps to reproduce

Generate Go Client with Swagger generator

Related issues/PRs

#7751

Suggest a fix/enhancement

When it now comes to decoding the response of the endpoint the generate Golang code looks like:

func (a *AdministrationApiService) AboutVersionGet(ctx context.Context) (string, *http.Response, error) {
	var (
		localVarHttpMethod  = strings.ToUpper("Get")
		localVarPostBody    interface{}
		localVarFileName    string
		localVarFileBytes   []byte
		localVarReturnValue string
	)

	// create path and map variables
	localVarPath := a.client.cfg.BasePath + "/about/version"

	localVarHeaderParams := make(map[string]string)
	localVarQueryParams := url.Values{}
	localVarFormParams := url.Values{}

	// to determine the Content-Type header
	localVarHttpContentTypes := []string{"application/json"}

	// set Content-Type header
	localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes)
	if localVarHttpContentType != "" {
		localVarHeaderParams["Content-Type"] = localVarHttpContentType
	}

	// to determine the Accept header
	localVarHttpHeaderAccepts := []string{"text/plain"}

	// set Accept header
	localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts)
	if localVarHttpHeaderAccept != "" {
		localVarHeaderParams["Accept"] = localVarHttpHeaderAccept
	}
	r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes)
	if err != nil {
		return localVarReturnValue, nil, err
	}

	localVarHttpResponse, err := a.client.callAPI(r)
	if err != nil || localVarHttpResponse == nil {
		return localVarReturnValue, localVarHttpResponse, err
	}

	localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body)
	localVarHttpResponse.Body.Close()
	if err != nil {
		return localVarReturnValue, localVarHttpResponse, err
	}

	if localVarHttpResponse.StatusCode < 300 {
		// If we succeed, return the data, otherwise pass on to decode error.
                //added by issue author: normal cast form byte to string would be enough if Content-Type is plain-text
		err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type"))
		return localVarReturnValue, localVarHttpResponse, err
	}

	if localVarHttpResponse.StatusCode >= 300 {
		newErr := GenericSwaggerError{
			body:  localVarBody,
			error: localVarHttpResponse.Status,
		}

		if localVarHttpResponse.StatusCode == 200 { //added by issue author: is this even reachable?
			var v string
			err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type"))
			if err != nil {
				newErr.error = err.Error()
				return localVarReturnValue, localVarHttpResponse, newErr
			}
			newErr.model = v
			return localVarReturnValue, localVarHttpResponse, newErr
		}

		if localVarHttpResponse.StatusCode == 400 {
			var v ErrorMessage
			err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type"))
			if err != nil {
				newErr.error = err.Error()
				return localVarReturnValue, localVarHttpResponse, newErr
			}
			newErr.model = v
			return localVarReturnValue, localVarHttpResponse, newErr
		}

		if localVarHttpResponse.StatusCode == 500 {
			var v ErrorMessage
			err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type"))
			if err != nil {
				newErr.error = err.Error()
				return localVarReturnValue, localVarHttpResponse, newErr
			}
			newErr.model = v
			return localVarReturnValue, localVarHttpResponse, newErr
		}

		return localVarReturnValue, localVarHttpResponse, newErr
	}

	return localVarReturnValue, localVarHttpResponse, nil
}

The problem here is that the decode() function only is able to decode xml or JSON data.
What we need is cast from byte to string if the contenttype is text/plain

@ormissia
Copy link

ormissia commented Jul 8, 2021

I had the same issue.

I think we should add the choice of strings.Contains(contentType, "text/plain") to the decode function in client.go that is generated by template file client.mustache.

It should be modified to look like this:

func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) {
	if strings.Contains(contentType, "application/xml") {
		if err = xml.Unmarshal(b, v); err != nil {
			return err
		}
		return nil
	} else if strings.Contains(contentType, "application/json") {
		if err = json.Unmarshal(b, v); err != nil {
			return err
		}
		return nil
	} else if strings.Contains(contentType, "text/plain") {
		// I'm not sure that's going to cause panic
		*(v.(*string)) = string(b)
		return nil
	}
	return errors.New("undefined response type")
}

In order to return the message directly when the contentType is text/plain.

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

2 participants