Golang Go语言中api数据返回过滤不需要的字段
Golang Go语言中api数据返回过滤不需要的字段
目前在用 gin+gorm 写一个小玩意,遇到这样的情况:
为了代码复用及写起来方便,基本都是用的 orm select *
有时候面向前台的接口不方便展示数据集中的某个字段,但是面向后端的又需要
这应该是前后端分离都会遇到的吧,请教各位大佬,比较好的解决方案是什么?
Graphql,https://graphql.org/code/#go
更多关于Golang Go语言中api数据返回过滤不需要的字段的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢,目前用的 restful api,我了解一下
重写一个结构体,然后将查询出来的 model 数据转移吗。
DTO ?
var u User =…
//举例:隐藏 User 里的 password
var out = struct{
User
Hide1 bool json:"password,omitempty"
}{
User: u,
}
json.Marshal(out)
//原理:利用 omitempty 属性的空值同名字段覆盖
这个 Google 一下就有了吧。可以重新定义结构体的 JSON 相关方法
后端处理后再返回,每一个字段都要处理,确保返回的数字是数字,字符是字符。
另外很多时候还会返回对象,举例帖子详情接口,返回的 author 就需要是一个对象,方便展示昵称和头像
{
“id”: 123,
“title”: “帖子标题”,
“author”:{
“id”: 456,
“name”: “帖子作者昵称”,
“avatar”: “帖子作者头像 URL”
}
}
嗯,感觉这个挺好的
json: - , binding: password,required
表设计好,索引用好并不会有什么问题…
很简单,换 PHP 就好了!(* ̄ rǒ ̄)
这个 ORM 都有的吧,比如 django 的 values(fields, *expressions)
看错了,此条无视
我的实践上还是返回的 model 和数据表的 model 会转一下,方便点,改表也没有心理压力
.NET 有 DTO,其他语言应该也有类似的,思路就是用中间类转换一下
先不说 select *的问题,你是把数据直接怼进 map 里?
创建一个专门用于输出数据的类,不要直接输出实体
使用 tag+reflect,根据请求 fields 返回需要的字段
很多种情况下都会出现操作的数据对象是一样的,就是需要的字段不同,不 select * 每个地方都要写一次,代码复用超级低。其实 OOP 思想也会有类似的问题,看怎么取舍了。
前台要求不展示 password,但是后台需要 password 怎么搞?写两个不同的 struct 然后转换?
dto vo po
如果出什么 bug,密码泄露到前台,你就知错了。
好的设计,就算出现 bug,也不至于出现敏感数据泄露。
安全距离是很重要的,你这种做法,不安全。
能贴一下做的比较好示例代码或示例项目吗?
正在写的过程中,我知道这样做肯定是不好的,所以来这里寻求比较好(方便,高效)的解决方案
一楼正解。
// models/user.go
struct User {
username string
password stirng
age int
…
}
// responses/user.go
struct UserResponse {
username string
age int
…
}
func NewUserResponse(user *User) {
…
}
// handlers/user.go
funct ReadUserHandler(req, res) {
user = models.ReadUserById(req.UserId)
return response.NewUserResponse(user)
}
简单的说,就是你们少了一层抽象:API response 。加上之后 API 返回字段就只和 API response 层相关,不需要和 model 、logic 层耦合(甚至 model 用 ORM 实现、甚至存储换成 redis/mongodb 也不会影响前端)。
是不是可以理解为 response 就是定义数据返回格式的,有几处不同的返回格式就定义几个 response,NewRespons 没有实际输出,只是进行数据重组?
举个例子,假设需要分别返回“课程信息”给 PC 端和 APP 端,他们需要返回的字段详细程度是不一样的,可以这样做
查询课程 ID -> 查询出该课程的详细信息 -> 缓存到某个地方(例如 ES ) -> 通过 Graphql 分别取各个端需要的字段信息 -> 返回给端
更新课程 ID -> 更新 DB 中的课程信息 -> 更新 ES 中的课程信息
不建议将数据库的 model 直接返回, 一般会定义一个 controller 层的 model, 这样的数据字段更具有灵活性,也更安全
这么多人推荐 Graphql,很有诱惑力
指定 Select 字段,它不香麽?
VO,DTO,各种结构职责分离
添加 exclude 或者 include 选项
https://github.com/pengwenwu/gin-items
不介意的话可以看下我自己写的小项目,基于 gin 的 restfull 风格的商品服务。
不定字段可以通过 scan 转到 map 里,不过性能会有影响
NewUserResponse 是其他语言中的构造函数,这样对生成的 UserResponse 可控(甚至 UserResponse 可以设计为 private 的 userResponse )。
UserResponse 也是可以复用的,下面这个例子就会复用 BasicUser 。
用户列表可能就只需要 BasicUser (用户名、头像),
查看用户详情时可能需要 UserDetail (BasicUser + 粉丝数、文章数),
查看自己的详情时可能需要 Me ( UserDetail + 收入 + 草稿箱中的文章数)。
struct BasicUser {
username string
avatar url
}
// API readUser
struct UserDetail {
UserResponse
bio string
location string
n_follower int
n_following int
n_posts int
}
// 用户查看自己信息的时
struct Me {
UserDetail
n_fav_posts int
total_cost double
total_income double
n_draft_posts int
}
// API listUser
struct UserList {
users BasicUser[]
}
https://colobu.com/2017/06/21/json-tricks-in-Go/
刚好前段时间忘了在哪收藏的一篇文章,有楼主需要的
感谢,很有用!
其实对 password 字段 omitempty 然后在 response 时直接给它赋值为空就完事了…我
#11 的回复似乎是有问题的,我当时没查证,抱歉。
在Go语言中处理API数据返回时,如果需要过滤掉不需要的字段,通常可以采用以下几种方法:
-
结构体标签(Struct Tags): 使用JSON结构体标签来控制哪些字段被序列化到JSON中。例如,如果你有一个结构体字段不需要在JSON响应中返回,可以在该字段的标签中设置
"json:"-"
。type MyStruct struct { ID int `json:"id"` Name string `json:"name"` Secret string `json:"-"` // 这个字段不会被序列化到JSON中 }
-
自定义序列化: 实现
json.Marshaler
接口,手动控制序列化的过程。这样可以完全自定义哪些字段被包含在最终的JSON数据中。 -
映射(Mapping): 创建一个新的结构体,只包含需要返回的字段,然后将数据从原始结构体复制到新结构体中。这种方法适用于需要动态决定哪些字段被返回的场景。
-
使用第三方库: 利用如
jsoniter
等高性能JSON处理库,它们可能提供了更灵活和高效的字段过滤功能。
选择哪种方法取决于你的具体需求,比如是否需要动态过滤字段、性能考虑等。在大多数情况下,使用结构体标签是最简单且直观的方法。如果需求更复杂,可以考虑实现自定义序列化或使用映射技术。