#development #golang #mac

In our previous article, we learned how to setup a connection to the Apple App Store Connect API with Golang. Today, we are going to refine this a little by adding support for parsing the error responses.

If you issue an incorrect request or something goes wrong, you'll get a response similar to this:

 1{
 2    "errors": [
 3        {
 4            "status": "404",
 5            "code": "NOT_FOUND",
 6            "title": "The specified resource does not exist",
 7            "detail": "The path provided does not match a defined resource type."
 8        }
 9    ]
10}

As you can see based on the JSON data, you can get multiple errors for a single request. I defined the error parsing like this:

 1package main
 2
 3import (
 4    "fmt"
 5    "strings"
 6)
 7
 8type ErrorResponse struct {
 9    Errors []Error `json:"errors"`
10}
11
12func (e *ErrorResponse) Error() string {
13    msgs := []string{}
14    for _, err := range e.Errors {
15        msgs = append(msgs, err.Error())
16    }
17    return strings.Join(msgs, "\n")
18}
19
20type Error struct {
21    Code   string `json:"code"`
22    Status string `json:"status"`
23    ID     string `json:"id"`
24    Title  string `json:"title"`
25    Detail string `json:"detail"`
26}
27
28func (e *Error) Error() string {
29    return fmt.Sprintf("%s | %s | %s", e.Status, e.Title, e.Detail)
30}

So, after we have obtained the bytes from the response, we can check the status code of the HTTP request. If it's not a code between 200 and 299, we consider that the response will contain an error. We can parse it like this:

 1resp, err := client.Do(req)
 2if err != nil {
 3    log.Fatal(err)
 4}
 5defer resp.Body.Close()
 6
 7bytes, err := ioutil.ReadAll(resp.Body)
 8if err != nil {
 9    log.Fatal(err)
10}
11
12if c := resp.StatusCode; c < 200 || c > 299 {
13    var errResponse ErrorResponse
14    if err := json.Unmarshal(bytes, &errResponse); err != nil {
15        log.Fatal(err)
16    }
17    log.Fatal(errResponse)
18}

We first read all the bytes as we want to store them for later one. You can decode the JSON directly from the response if you want to, but I prefer to keep it in a variable for now. We then check the status code and parse the JSON into an ErrorResponse struct. Since ErrorResponse implements the Error interface, we can simply log it as an error. The output is then something like:

2020/12/20 15:02:28 404 | The specified resource does not exist | The path provided does not match a defined resource type.

Next time, we'll look into how to read a successful response.