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

Read APIError response body #121

Open
mxinden opened this issue Oct 26, 2018 · 9 comments
Open

Read APIError response body #121

mxinden opened this issue Oct 26, 2018 · 9 comments
Labels

Comments

@mxinden
Copy link

mxinden commented Oct 26, 2018

I make a request via a client generated based on a swagger spec generated via the goswagger.io project with an invalid json property. The back-end returns a HTTP 422 with details in the response body. Reading the response body is crucial to debug the problem.

go-openapi/runtime/client/runtime.go.Submit() calls readResponse.ReadResponse which returns an APIError with the response body embedded:

return readResponse.ReadResponse(response{res}, cons)

type APIError struct {
OperationName string
Response interface{}
Code int
}

Problem is, that this embedded response body is closed via a defer in go-openapi/runtime/client/runtime.go.Submit():

defer res.Body.Close()

Thereby casting the error and reading the response body later on fails with http: read on closed response body:

apiError, ok := err.(*runtime.APIError)
if !ok {
	// handle
}

response, ok := apiError.Response.(runtime.ClientResponse)
if !ok {
	// handle
}

body, err := ioutil.ReadAll(response.Body())
if err != nil {
	// fails with "http: read on closed response body"
}

fmt.Println(string(body))

How can I access the APIError response body? Might it be possible to embed the body as a string inside the APIError? Let me know if you need more info.

@mxinden
Copy link
Author

mxinden commented Nov 8, 2018

@casualjim any thoughts on this?

@bdazl
Copy link

bdazl commented Jan 8, 2019

I'm having problem with this also. As an outsider of this project, it seems like the func (*APIError) Error() should handle this similarly to how @mxinden handles the error (with some fix to the stated error). To me, the error provided by this function is not sufficient.

@casualjim
Copy link
Member

you have to provide the error datastructure in the definitions, so that it gets picked up
or put a schema of type: object for the response body schema

the mixin tool lets you edit a spec by deep merging another one, in case the spec isn't under your control.

@bdazl
Copy link

bdazl commented Jan 9, 2019

Ignore my ranting, my problem is actually 'just' that of @mxinden . If I just print the error by the APIError's own error function, I get this:
unknown error (status 500): {resp:0xc0000ae3f0}

When I @mxinden 's approach to explicitly read the body of the ClientResponse I get http: read on closed response body

@deeptibaghel
Copy link

I am facing the same issue, reading the response body is a must in my application. Is there any solution available ?

@fredbi
Copy link
Member

fredbi commented Apr 10, 2019

@deeptibaghel There is no problem reading a response body, including error responses.
You just have to define your response with a non empty schema.

Like this:

responses:
  badRequest:
    description: client error in request
    schema:
      type: object
      properties:
        errorMessage:
          type: string

If you expect a generic object, do this like:

responses:
  badRequest:
    description: client error in request
    schema:
      type: object
      additionalProperties: true

@deeptibaghel
Copy link

Thanks @fredbi , so my swagger yaml file should have it and then the client will generate methods to read it right ?

@fredbi
Copy link
Member

fredbi commented Apr 10, 2019

Yes. You just have to insert some type assertion switch on the returned error to set it to the underlying error type and you are good to work with the content.

Something like this (example without switch and without actually using the content):

if _, notFound := erp.(*operations.GetRolesByIDRoleIDNotFound); notFound {
				// looks like this has disappeared since last fetched: skip
				continue
}

@deeptibaghel
Copy link

Many Thanks @fredbi

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