I have an endpoint similar to GET ../produtcs/123
where 123 stands for an ID. The REST service response
- with either
status 200
and a json object A{"deliveryData": {"status": 200, ...}}
- or with
status 401
and a json object B{"error": "foo", "status": 401, ...}
There are similar question (1, 2, 3, 4) but in my case i can not change the endpoint that i have to call.
What i would like to know is how my go-client code to call this endpoint should handle the different responses?
Currently i return a string of the response
func getProductResponse(tokenResponse *TokenResponse, id string) (string, error) {
endpoint := "https://httpbin.org/json"
req, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
return "Creation of Request failed", err
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "client.Do(req) failed", err
}
defer func() {
if err := resp.Body.Close(); err != nil {
fmt.Println("Error closing response body:", err)
}
}()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return "io.ReadAll(resp.Body) failed", err
}
return string(responseBody), nil
}
And the idea is to handle the response by something like this
func handleResponse(jsonStr string){
var product Product
var idError Error
if err := json.Unmarshal([]byte(jsonStr), &product); err == nil {
fmt.Println("JSON can be converted to Product")
} else if err := json.Unmarshal([]byte(jsonStr), &idError); err == nil {
fmt.Println("JSON can be converted to Error")
} else {
fmt.Println("JSON does not match either Product nor Error")
}
}
Example
productStr := `{"deliveryData": {"status": 200}}` // product found
idErrorStr := `{"error": "Id unknown", "status": 401}` // product not found
// id of product found
handleResponse(productStr)
// id not found
handleResponse(idErrorStr)
But i wonder if this is a bad design, since it does not take care of the different return types in the function that calls the endpoint.
How would you handle these two different responses?
1 Answer 1
How you handle this depends on what you can do with the response data in the case you get a 401
from the server. REST does not obligate you to parse the response from the server. You won't get any meaningful guidance there. Instead, consider the use case in your application. You get a 401 Unauthorized
response from the server, which means the user is not authorized. If the error property of the JSON response contains an error you want to log, or display to the end user, then you'll need to change the destination data type when parsing the JSON response.
I'm not familiar with Go, but the general strategy is:
if response.status := 200 {
var response Product = json.Unmarshal([]byte(jsonStr), &response)
// Success, do the "happy path" for your use case
}
else if response.status := 401 {
var response Error = json.Unmarshal([]byte(jsonStr), &response)
// do something with response.error or show login screen
}
This might not be completely valid Go, but hopefully this illustrates the basic process.
Your question seems to assume a 401
response from the server means the product was not found, but it means Unauthorized. Perhaps you meant 404 Not Found? Even then, my answer stands: you need to tailor your code to that use case.
-
They indeed sent
401
instead of404
i do not know why - bad knowledge of http codes orSecurity through obscurity
surfmuggle– surfmuggle2024年03月04日 23:24:13 +00:00Commented Mar 4, 2024 at 23:24 -
@surfmuggle I am not quite sure that is the case. 401 has a very specific meaning. In this case it could well be that the ID is reported as unknown because you do not have the permission to access it. I admit that the semantics are quirky, but I can definitely see a situation in which 401 is the actual reason and the message is just... improvable.Markus W Mahlberg– Markus W Mahlberg2025年04月21日 09:48:45 +00:00Commented Apr 21 at 9:48
Explore related questions
See similar questions with these tags.