Home > Mobile >  Dynamically handling the responses
Dynamically handling the responses

Time:08-17

I am trying to dynamically manage the error and get the appropriate message. There are two sort of error responses - below shared:

  • Error Type 1
    {
      "error": "This is bad request"
    }
    
  • Error Type 2
    {
      "error": {
        "message": "This is error message"
      }
    }
    

    I tried with various answers on stackoverflow. But couldn't reach a possible solution. With the code I have currently, its working for one - Error Type 2.

    For Error Type 1, I am getting error:

    panic: reflect: Elem of invalid type string
    
    goroutine 1 [running]:
    reflect.(*rtype).Elem(0x100a88a80)
            /usr/local/go/src/reflect/type.go:954  0x194
    main.main()
            /Users/username/Documents/dev/go/prac.go:31  0x104
    exit status 2
    

    For Error Type 2, I am getting perfect output:

    This is error message
    
    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    func main() {
    
        // Error Type: 1
    
        str1 := "{\"error\":\"This is bad request\"}"
        var errResp interface{}
        json.Unmarshal([]byte(str1), &errResp)
    
        // ------------------------------------------------------------------------
    
        // Error Type: 2
    
        // str2 := "{\"error\": {\"message\": \"This is error message\"}}"
        // var errResp interface{}
        // json.Unmarshal([]byte(str2), &errResp)
    
        // ------------------------------------------------------------------------
    
        // Handling both type dynamically
    
        errResponse := errResp.(map[string]interface{})
        realErr := errResponse["error"]
        if reflect.TypeOf(realErr).Elem().Kind() == reflect.String {
            // I have used fmt.Sprint here, because I will have to
            // return it as string in my original implementation.
            fmt.Println(fmt.Sprint(realErr))
        }
        lastRealErr := realErr.(map[string]interface{})
        fmt.Println(fmt.Sprint(lastRealErr["message"]))
    }
    
    

    Here ^, I have combined the code for both the error types. To test it you will just have to comment one and uncomment the other to test.

    Can you please help me out here? Thank you.

  • CodePudding user response:

    Declare a custom type for the error and have it implement the json.Unmarshaler interface. In the implementation you can look at the raw data and, based on what the data seems to contain, decide on how to unmarshal it.

    type response struct {
        Error responseError
    }
    
    type responseError struct {
        Message string
    }
    
    func (e *responseError) UnmarshalJSON(data []byte) error {
        if len(data) == 0 || string(data) == `null` { // nothing?
            return nil
        }
        if data[0] == '"' && data[len(data)-1] == '"' { // string?
            return json.Unmarshal(data, &e.Message)
        }
    
        // avoid infinite recursion by declaring a new type
        // with same structure as responseError but no methods.
        type E responseError 
        return json.Unmarshal(data, (*E)(e))
    }
    

    The encoding/json package will automatically invoke the UnmarshalJSON method when it encounters a valid instance of json.Unmarshaler in the target value.

    https://go.dev/play/p/jWzRSsSuN65

    •  Tags:  
    • go
    • Related