Reputation: 1665
We are adding an include parameter in our API w/c API clients can use to include relationships
// request
GET /api/events?include=team1
[{
"id": <event_id>,
"name": <event_name>,
"team1": {
"id": <team_id>,
"name": <team_name>
}
}]
// code
type Event struct {
ID int64 `gorm:"primary_key" json:"id"`
Team1ID int64 `json:"-"`
Team1 Team `json:"team1"`
}
var event Event
Db.Preload("Team1").Find(&event, 1)
c.JSON(http.StatusOK, event)
But we also want to be able to do this:
// request
GET /api/events
[{
"id": <event_id>,
"name": <event_name>,
"team1": <team1_id>
}]
The team1 field is now just an id.
Is there an easy way to do this in Go?
I think I can do this by using a map[string]interface{}
, like after fetching the events in the db, convert the event structs to a map[string]interface{}
and do the modifications. But I'm wondering if theres an easier solution.
Here's my attempt in using map[string]interface{}
- https://play.golang.org/p/-19MWtqhE3 . The code is very verbose. The idea is to use map[string]interface{}
for every struct then compose the top level resource that includes the related resources.
What's a better way to do this?
Upvotes: 1
Views: 1822
Reputation: 164
Actually you could just set the team1 to be an interface and then cast it's value, obviously making the proper validations.
type Event struct {
ID int64 `gorm:"primary_key" json:"id"`
Team1ID int64 `json:"-"`
Team1 interface{} `json:"team1"`
Team1Struct Team `json:"-"`
}
And then evaluate:
if value, ok := evt.Team1.(Team); ok {
// The passed value is a Team struct
event.Team1Struct = value
} else {
// The passed value is a string (or something else...)
}
Upvotes: 1
Reputation: 557
I think the most cleaner way is to use two different functions.
type Event struct {
ID int64 `gorm:"primary_key" json:"id"`
Team1ID int64 `json:"-"`
Team1 Team `json:"team1"`
}
type Team struct {
ID int64 `gorm:"primary_key" json:"id"`
Name string `json:"name"`
}
type EventInformations struct {
ID int64 `json:"id"`
Name string `json:"name"`
Team1 `json"team1"`
}
type EventInformationsTeamIncluded struct {
ID int64 `json:"id"`
Name string `json:"name"`
Team1 Team `json:"team1"`
}
func (e *Event) Informations() *EventInformations {
return &EventInformations{
ID: e.ID,
Name: e.Name,
Team1: e.Team1,
},
}
func (e *Event) InformationsTeamIncluded() *EventInformationsTeamIncluded {
return &EventInformations{
ID: e.ID,
Name: e.Name,
Team1: &Team{
...
},
}
}
So later just call
event.Informations();
Or
event.InformationsTeamIncluded();
There is something not very logical in your code/examples:
Team1
is a little bit weird cause there is only one value in the struct so if you don't have plan to add some Team
in struct I suggest to replace it by Team if you plan to have any Team replace it by Teams []*Team
team1_id
instead of team1
EDIT : without struct
func (e *Event) Informations() *map[string]interface{} {
return &map[string]interface{}{
"ID": e.ID,
"Name": e.Name,
"Team1": e.Team1,
},
}
func (e *Event) InformationsTeamIncluded() *map[string]interface{} {
// Reuse the previous function
data := e.Informations()
// Add the team1 informations
data["team1"] = map[string]interface{}{
ID: e.Team1.ID,
Name: e.Team1.Name,
}
return data
}
Upvotes: 1