什么是支持Go中动态结构字段的干净解决方案?

时间:2017-02-11 09:29:37

标签: json rest go

计划重构我们去年建立的应用程序的代码库。让我们说这个api端点w / c支持包括相关资源GET /api/leagues?include=sport。是否有更简洁的方法可以在api响应中使sport资源的league属性动态化? sport属性的值可以是int或Sport结构。目前,这就是我们正在做的事情:

// models/league.go
type League struct {
  SportId int64 `json:"-"`
  Sport Sport `json:"-"`
  SportWrapper interface{} `json:"sport"`
}

// controllers/league.go
include := c.Request.URL.Query().Get("include")
includes := strings.Split(include, ",")

for _, include := range includes {
  if include == "sport" {
    includeSport = true
  }
}

if includeSport {
  league.SportWrapper = league.Sport
} else {
  league.SportWrapper = league.SportId
}

c.JSON(http.StatusOK, league)

对api请求的回应:

{
  sport: {
    id: <id>,
    name: <name>
  }
}

它也可以是:

{
  sport: <sport_id>
}

2 个答案:

答案 0 :(得分:1)

没有更多背景,很难说。我假设SportId也是Sport结构的一部分。您基本上只返回ID或整个结构。

我建议只添加

Sport Sport `json:"-"`

结构。而不是直接将其序列化为json,您必须首先使用固定属性集创建一个映射(基本上是一个视图模型)。在那里你可以设置你的SportID或Sport结构,之后你可以将地图序列化为json。

这也不是一个非常好的解决方案,但优势在于,在您当前的解决方案中,响应代码的丑陋会泄漏到数据模型中,从而泄漏到应用程序的其余部分。使用中间映射,丑陋的部分被限制在响应生成中。

// models/league.go
type League struct {
  Sport Sport
}

... parse includes ...

viewModel := map[string]interface{}

if includeSport {
  viewModel["sport"] = league.Sport
} else {
  viewModel["sport"] = league.Sport.ID
}

c.JSON(http.StatusOK, viewModel)

答案 1 :(得分:0)

// models/league.go
type League struct {
    SportID int64 `json:"-"`
    Sport Sport `json:"-"`
    SportWrapper interface{} `json:"sport"`
}


var (
    sportID int
    sport Sport
)
// controllers/league.go
include := c.Request.URL.Query().Get("include")
if err := json.Unmarshal([]byte(unclude), &sportID); err != nil {
    json.Unmarshal([]byte(unclude), &sport)
    league.SportWrapper = sport
    league.Sport = sport
} else {
    league.SportWrapper = sportID
    league.SportID = sportID
}

c.JSON(http.StatusOK, league)

如果你可以将你的请求参数设置为json,你可以使用它。