I'm trying to encode some JSON for a REST api, everything is working fine except for some errors. For example, with this struct:
type TemplateResponse struct {
Message string
Error error
Template Template
}
Encoded with this data:
res := TemplateResponse{"Template not found.", fmt.Errorf("There is no template on this host with the name " + vars["name"]), Template{}}
json.NewEncoder(w).Encode(res)
Returns:
{
"Message": "Template not found.",
"Error": {},
"Template": {
"Name": "",
"Disabled": false,
"Path": "",
"Version": ""
}
}
I'm getting this seemingly randomly across my application, where 'error' types are being returned as empty. Any ideas?
Thanks!
Because error
is just an interface. It may hold a value of any concrete type that implements it.
In your example you used fmt.Errorf()
to create an error
value. That calls errors.New()
which returns a pointer to a value of the unexported errors.errorString
struct. Its definition is:
type errorString struct {
s string
}
This struct value will be marshaled, but since it has no exported fields (only exported fields are marshaled), it will be an empty JSON object: {}
.
The "fix" is: don't marshal values of "general" interfaces, relying on that the dynamic values can be marshaled into JSON meaningfully. Instead you should add a field that stores the error string (the result of error.Error()
), and omit the Error error
field from marshaling, e.g.:
type TemplateResponse struct {
Message string
Error error `json:"-"`
ErrorMsg string
Template Template
}
Of course then you also need to set / fill the ErrorMsg
field before marshaling.
Or if you don't need to store the error
value in the struct, remove that field completely:
type TemplateResponse struct {
Message string
ErrorMsg string
Template Template
}
If you still want to keep the Error error
field (and not the ErrorMsg
field), then you need to implement a custom marshaling logic by implementing the json.Marshaler
interface where you can "convert" the error
value to a meaningful string
for example (or into another value that can be marshaled properly).