0

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 -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

6

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.

1
  • They indeed sent 401 instead of 404 i do not know why - bad knowledge of http codes or Security through obscurity
    – surfmuggle
    Commented Mar 4 at 23:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.