go-openapi / runtime

openapi runtime interfaces

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to get the client response?

GaoJianAllen opened this issue · comments

I received an error response from the client side.
I try to parse the response from runtime.APIError.
However, the type of Response is interface and deeper type is client.response.
It is lowercase and private.

So how to get the response? I just want to get http.Response.
https://github.com/go-openapi/runtime/blob/master/client_response.go#L59
https://github.com/go-openapi/runtime/blob/master/client/response.go#L29

You can access some fields of http.Response via these methods:

func (r response) Code() int {
return r.resp.StatusCode
}
func (r response) Message() string {
return r.resp.Status
}
func (r response) GetHeader(name string) string {
return r.resp.Header.Get(name)
}
func (r response) GetHeaders(name string) []string {
return r.resp.Header.Values(name)
}
func (r response) Body() io.ReadCloser {
return r.resp.Body
}

Would you like to access something else?

You can access some fields of http.Response via these methods:

func (r response) Code() int {
return r.resp.StatusCode
}
func (r response) Message() string {
return r.resp.Status
}
func (r response) GetHeader(name string) string {
return r.resp.Header.Get(name)
}
func (r response) GetHeaders(name string) []string {
return r.resp.Header.Values(name)
}
func (r response) Body() io.ReadCloser {
return r.resp.Body
}

Would you like to access something else?

Thank you for replying. I try to use below code to get response.

`

if apiErr, ok := err.(*runtime.APIError); ok {
if resp, ok := apiErr.Response.(interface{ Body() io.ReadCloser }); ok {
body := resp.Body()
bs, ee := io.ReadAll(body)
if ee != nil {
return ee
}
fmt.Printf(string(bs))
}
}
`
However, the io.ReadCloser is closed so that I can't read the original message.

So it doesn't resolve my scenario.

My case is thatm the service doesn't define an error(e.g. 401) in yaml spec. So I can't read the body of the request to parse the message. If I use go-swagger framework, it will lose the message

How about using a client option to intercept the response? For example, define these functions:

func errorHandler(r runtime.ClientResponseReader) runtime.ClientResponseReaderFunc {
	return func(res runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
		if res.Code() >= 400 {
			return nil, runtime.NewAPIError(res.Message(), res, res.Code())
		}
		return r.ReadResponse(res, consumer)
	}
}

func withErrorHandler(req *runtime.ClientOperation) {
	req.Reader = errorHandler(req.Reader)
}

And use withErrorHandler when calling an API like this:

res, err := client.Default.Operations.GetSomething(operations.GetSomethingParams(), withErrorHandler)

Then the returned runtime.APIError should have an io.ReadCloser that is not consumed yet.

You can also read the body inside errorHandler like this:

func errorHandler(r runtime.ClientResponseReader) runtime.ClientResponseReaderFunc {
	return func(res runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
		if res.Code() >= 400 {
			//TODO: read `res.Body()` and return an appropriate error.
		}
		return r.ReadResponse(res, consumer)
	}
}

It'll save you from casting errors.

@jkawamoto That resolves my problem. Thank you a lot!