I am trying to dynamically manage the error and get the appropriate message. There are two sort of error responses - below shared:
{
"error": "This is bad request"
}
{
"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.