Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide properties from a JSON

Tags:

json

go

I have a struct Table with 2 Players, but I need to ignore some properties from the struct Player when I send JSON.

I could use json:"-", but then the property will be ignored ALWAYS, and I need to ignore it only when I send the Table struct. I need those properties when I send the Player in other parts of the code.

I have:

type Player struct {
    Id            Int64   `json:"id"`
    Username      string  `json:"username,omitempty"`
    Password      string          `json:"-,omitempty"`
    Email         string          `json:"email,omitempty"`
    Birthdate     time.Time       `json:"birthdate,omitempty"`
    Avatar        string  `json:avatar,omitempty"`
}

type Table struct {
    Id           int       `json:"id"`
    PlayerTop    Player      `json:"playerTop"`
    PlayerBottom Player      `json:"playerBottom"`
}

I need:

{
    "Table": {
        "id": 1,
        "playerBottom": {
            "id": 1,
            "username": "peter",
            "avatar": "avatar.png"
        },
        "playerTop": {
            "id": 1,
            "username": "peter",
            "avatar": "avatar.png"
        }

    }
}

The players come from the database, so the properties aren't empty.

a) I could do something like:

myTable = new(Table)

myTable.PlayerBottom.Email = ""
myTable.PlayerBottom.Birthdate = ""
myTable.PlayerTop.Email = ""
myTable.PlayerTop.Birthdate = ""

so those properties will be ignored in the JSON, thanks to json:"omitempty", but this is a bad idea.

b) I could use something like an alias struct but Table is expecting that PlayerBottom is of type Player not PlayerAlias, but I don't know how to implement it:

type PlayerAlias struct {
    Id            Int64   `json:"id"`
    Username      string  `json:"username,omitempty"`
    Avatar        string  `json:avatar,omitempty"`
}

c) I tried to add dynamically json:"-" to the properties that I don't want from the JSON before to send it, but it was a mess.

like image 216
gnutella Avatar asked Feb 18 '19 16:02

gnutella


People also ask

How to ignore properties in json?

To ignore individual properties, use the [JsonIgnore] attribute. You can specify conditional exclusion by setting the [JsonIgnore] attribute's Condition property. The JsonIgnoreCondition enum provides the following options: Always - The property is always ignored.

Should JSON properties be LowerCase?

property names must start with lower case letter. Dictionary must be serialized into jsonp where keys will be used for property names. LowerCase rule does not apply for dictionary keys.


1 Answers

You could create a custom Marshaler for Table types. This is the interface you have to implement:

https://golang.org/pkg/encoding/json/#Marshaler

type Marshaler interface {
        MarshalJSON() ([]byte, error)
}

Then you'd remove the - tag from Player (because when you marshal it elsewhere you need to preserve the fields) and only ignore it in the custom MarshalJSON method of Table.


Here's a simple (unrelated) example of implementing custom marshaling for a type, encoding one of the fields in hex:

type Account struct {
    Id   int32
    Name string
}

func (a Account) MarshalJSON() ([]byte, error) {
    m := map[string]string{
        "id":   fmt.Sprintf("0x%08x", a.Id),
        "name": a.Name,
    }
    return json.Marshal(m)
}

func main() {
    joe := Account{Id: 123, Name: "Joe"}
    fmt.Println(joe)

    s, _ := json.Marshal(joe)
    fmt.Println(string(s))
}

As you can see here, such marshaling is easy to do by constructing a map with just the fields you need and passing it to json.Marshal. For your Table and Player this will result in just a few lines of trivial code. IMHO it's better to do this than to modify the types and complicate them with embeddings/aliases, just for the sake of JSON encoding.

like image 131
Eli Bendersky Avatar answered Oct 11 '22 13:10

Eli Bendersky