Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One struct with multiple json representations

Tags:

json

go

The problem I'm trying to solve is that I have a model of a community that looks like this

type Community struct {
    Name string
    Description string
    Sources []Source
    Popularity int
    FavoriteCount int
    Moderators []string
    Children []Community
    Tracks []Track
}

Communities hold a lot of information and there are scenarios when I want to return only part of the description such as if I'm returning a list of trending communities. In this case I'd want to return only

type Community struct {
    Name string
    Description string
    Popularity int
    FavoriteCount int
}

The only way I can think of doing this is to create a new type containing only those fields and write a convenience method that takes a community and returns that type, but essentially creating a new object and copying those fields by value, is there a better way to do this?

I'm aware of the json:"-" syntax, but I'm not sure of how you could do this on a case by case basis as I still need to sometimes return the full object, perhaps a different type that is converted to?

like image 440
Matt Bucci Avatar asked Jul 16 '14 00:07

Matt Bucci


2 Answers

[This](http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/ ) is a cool approach, which involves creating a sort of Masking struct.

Here's the example in the article:

type User struct {
    Email    string `json:"email"`
    Password string `json:"password"`
    // many more fields…
}

type omit *struct{}

type PublicUser struct {
    *User
    Password omit `json:"password,omitempty"`
}

// when you want to encode your user:
json.Marshal(PublicUser{
    User: user,
})
like image 140
Karlie Verkest De Young Avatar answered Oct 01 '22 09:10

Karlie Verkest De Young


I developed a library which can help you in this regard: Sheriff

You can annotate your struct fields with special tags and call Sheriff to transform the given struct into a subset of it. After that you can call json.Marshal() or whatever else you want to marshal into.

Your example would become as simple as:

type Community struct {
    Name          string      `json:"name" groups:"trending,detail"`
    Description   string      `json:"description" groups:"trending,detail"`
    Sources       []Source    `json:"sources" groups:"detail"`
    Popularity    int         `json:"popularity" groups:"trending,detail"`
    FavoriteCount int         `json:"favorite_count" groups:"trending,detail"`
    Moderators    []string    `json:"moderators" groups:"detail"`
    Children      []Community `json:"children" groups:"detail"`
    Tracks        []Track     `json:"tracks" groups:"detail"`
}

communities := []Community{
    // communities
}

o := sheriff.Options{
    Groups: []string{"trending"},
}

d, err := sheriff.Marshal(&o, communities)
if err != nil {
    panic(err)
}

out, _ := json.Marshal(d)
like image 30
Michael Weibel Avatar answered Oct 01 '22 09:10

Michael Weibel