如何在输入中跳过Struct中的JSON字段并在输出中显示它们,并接受输入中的某些字段并在Golang的输出中跳过它们?

时间:2017-02-07 09:25:54

标签: json go struct go-gorm

我正在使用Echo框架和Gorm在Go中编写Web服务。 我有一个User结构,如下所示:

type User struct {
    ID    uint   `json:"user_id"`
    Email string `json:"email_address,omitempty" validate:"required,email"`
}

我接受POST次请求Content-type: application/json。 我希望我的输入为{"email_address": "email@email.com"},输出为{"user_id": 1}

如何禁止用户在请求中提交ID(因此他们无法创建包含某些ID的记录),但请在响应中保留ID? 现在我在保存之前正在做user.ID = 0,但我想知道是否有更好的方法可以做到这一点?

我还想在输出中跳过Email。现在我在输出之前做user.Email = ""。还有更好的方法吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

我通过使它更通用来扩展你的例子,并且我展示了更普遍问题的优雅解决方案。

我们假设在User中有:

  • 必须仅从输入
  • 解析的一些字段
  • 某些必须仅出现在输出中的字段
  • 并且有些字段必须从输入解析,而也必须出现在输出中

你的例子是"子集"这个(在你的例子中没有共同的字段)。

无需使用embedding重复字段即可优雅地解决此问题。您可以创建3种不同的类型;一个用于公共字段UserBoth,一个用于仅输入字段UserIn,另一个用于仅输出字段UserOut

type UserBoth struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

type UserIn struct {
    *UserBoth
    Email string `json:"email"`
}

type UserOut struct {
    *UserBoth
    ID uint `json:"id"`
}

请注意UserBoth(或更确切地说*UserBoth以避免重复结构值)嵌入UserInUserOut中,因为我们希望这两个字段都存在。< / p>

现在,如果您的输入包含所有字段(即使我们不想要所有字段):

const in = `{"name":"Bob","age":23,"Email":"as@as.com","id":123}`

解组为UserIn的值只会解析您想要的内容:

uin := UserIn{UserBoth: &UserBoth{}}
err := json.Unmarshal([]byte(in), &uin)
fmt.Printf("%+v %+v %v\n", uin, uin.UserBoth, err)

输出(请注意Email字段已解析,但ID不是

;

{UserBoth:0x1050e150 Email:as@as.com} &{Name:Bob Age:23} <nil>

当您想要生成输出时:

uout := UserOut{UserBoth: uin.UserBoth}
// Fetch / set ID from db:
uout.ID = 456
out, err := json.Marshal(uout)
fmt.Println(string(out), err)

输出(请注意,ID字段已存在,但Email不是

;

{"name":"Bob","age":23,"id":456} <nil>

Go Playground上尝试。

拥有&#34;统一&#34; User

上面的示例使用了2个不同的结构:UserIn用于解析,UserOut用于生成输出。

如果在您的代码中,您想使用&#34;统一&#34; User结构,这就是它的完成方式:

type User struct {
    UserIn
    UserOut
}

使用它:

uboth := &UserBoth{}
u := User{UserIn{UserBoth: uboth}, UserOut{UserBoth: uboth}}
err := json.Unmarshal([]byte(in), &u.UserIn)
fmt.Printf("%+v %+v %v\n", u, u.UserIn.UserBoth, err)

// Fetch / set ID from db:
u.ID = 456
out, err := json.Marshal(u.UserOut)
fmt.Println(string(out), err)

Go Playground上试试这个。

答案 1 :(得分:0)

虽然icza的答案提出了一个很好的解决方案,但您也可以使用JSON编组辅助方法MarshalJSON/UnmarshalJSON

func main() {
    // employing auxiliary json methods MarshalJSON/UnmarshalJSON
    user := User{ID: 123, Email: `abc@xyz.com`}
    js, _ := json.Marshal(&user)
    log.Printf("%s", js)

    input := UserInput(user)
    js, _ = json.Marshal(&input)
    log.Printf("%s", js)

    output := UserOutput(user)
    js, _ = json.Marshal(&output)
    log.Printf("%s", js)
}

type User struct {
    ID    uint   `json:"user_id"`
    Email string `json:"email_address,omitempty" validate:"required,email"`
}

type UserInput User

func (x *UserInput) MarshalJSON() ([]byte, error) {
    return json.Marshal(&struct {
        Email string `json:"email_address,omitempty" validate:"required,email"`
    }{
        Email: x.Email,
    })
}

type UserOutput User

func (x *UserOutput) MarshalJSON() ([]byte, error) {
    return json.Marshal(&struct {
        ID uint `json:"user_id"`
    }{
        ID: x.ID,
    })
}

这给了我们:

[  info ] main.go:25: {"user_id":123,"email_address":"abc@xyz.com"}
[  info ] main.go:29: {"email_address":"abc@xyz.com"}
[  info ] main.go:33: {"user_id":123}

Go Playground