Given the following code: ( reproduced here at play.golang.org .)
package main import ( "encoding/json" "fmt" ) type User struct { Id int `json:"id"` Name string `json:"name"` } type Session struct { Id int `json:"id"` UserId int `json:"userId"` } type Anything interface{} type Hateoas struct { Anything Links map[string]string `json:"_links"` } func MarshalHateoas(subject interface{}) ([]byte, error) { h := &Hateoas{subject, make(map[string]string)} switch s := subject.(type) { case *User: h.Links["self"] = fmt.Sprintf("http://user/%d", s.Id) case *Session: h.Links["self"] = fmt.Sprintf("http://session/%d", s.Id) } return json.MarshalIndent(h, "", " ") } func main() { u := &User{123, "James Dean"} s := &Session{456, 123} json, err := MarshalHateoas(u) if err != nil { panic(err) } else { fmt.Println("User JSON:") fmt.Println(string(json)) } json, err = MarshalHateoas(s) if err != nil { panic(err) } else { fmt.Println("Session JSON:") fmt.Println(string(json)) } }
I am trying to make the displayed JSON look correct in my case, it means something like:
User JSON: { "id": 123, "name": "James Dean", "_links": { "self": "http://user/123" } } Session JSON: { "id": 456, "userId": 123, "_links": { "self": "http://session/456" } }
Unfortunately, Go treats the anonymous element as a real named thing, so it takes a specific type ( Anything ) and calls JSON like this:
User JSON: { "Anything": { "id": 123, "name": "James Dean" }, "_links": { "self": "http://user/123" } } Session JSON: { "Anything": { "id": 456, "userId": 123 }, "_links": { "self": "http://session/456" } }
There are no clear documents about the processing of anonymous members in JSON, from documents :
Anonymous structure fields are usually marshalled as if their internal exported fields were fields in the external structure, provided that the usual Go visibility rules are followed, as described in the next paragraph. An anonymous structure field with the name specified in its JSON tag is considered to have that name, not anonymous.
Handling anonymous structure fields is new in Go 1.1. Prior to transition 1.1, anonymous structure fields were ignored. To force an anonymous structure field to be ignored in the current and earlier versions, give the field a JSON tag for "-".
This does not clarify if there is a way to smooth or hint to Marshaller what I am trying to do.
I am sure that there may be, as there is a special case, a magic name that is of particular importance for renaming the root element of an XML document in an XML marshaller.
In this case, I am also not bound to the code in any way, my use case should have a function that takes interface{}, *http.Request, http.ResponseWriter , and write HATEOAS documents by wire, switching the type passed, to output a link to JSON record. (thus, access to the request, for the host, port, scheme, etc. of the request, as well as for the type itself to display the URL and known fields, etc.)